Haskell:按类型过滤

时间:2016-03-16 11:00:11

标签: haskell

对于任何特定类型A

data A = A Int

可以编写这个函数吗?

filterByType :: a -> Maybe a

如果给出了Just . id类型的值,则应该返回A,而对于任何其他类型的值,它应该返回Nothing

使用任何手段(GHC exts,TH,introspection等)

NB。由于我的last question关于Haskell类型系统被社区批评为“非常过分简化”,我觉得有必要说明,这是对Haskell类型系统限制的纯粹学术兴趣,其背后没有任何特定任务需要解决。

3 个答案:

答案 0 :(得分:5)

您正在cast

寻找Data.Typeable
cast :: forall a b. (Typeable a, Typeable b) => a -> Maybe b 

相关问题here

实施例

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Typeable

data A = A Int deriving (Show, Typeable)
data B = B String deriving (Show, Typeable)

showByType :: Typeable a =>a ->String
showByType x = case (cast x, cast x) of
                 (Just (A y), _) ->"Type A: " ++ show y
                 (_, Just (B z)) ->"Type B: " ++ show z

然后

> putStrLn $ showByType $ A 4
Type A: 4
> putStrLn $ showByType $ B "Peter"
Type B: "Peter"
>

如果没有Typeable派生,没有关于基础类型的信息,您可以执行某些cast转换,例如

import Unsafe.Coerce (unsafeCoerce)

filterByType :: a -> Maybe a
filterByType x = if SOMECHECK then Just (unsafeCoerce x) else Nothing

但是,那些信息在哪里?

然后,你不能写你的功能(或者我不知道怎么做),但在某些情况下(二进制内存检查,模板haskell,......)可能是。

答案 1 :(得分:4)

不,你不能写这个功能。在Haskell中,没有类型类约束的值在其类型变量中是参数。这意味着我们知道在任何特定类型实例化时它们必须表现得完全相同¹;特别是,与您的问题相关,这意味着他们无法检查他们的类型参数。

这种设计意味着所有类型都可以在运行时擦除,GHC确实这样做。所以即使走出Haskell之外的Haskell,不安全的技巧也无法帮助你,因为运行时表示也是一种参数化的。

如果你想要这样的话,使用josejuan's suggestionTypeable操作的cast是一个很好的操作。

¹使用seq模拟一些细节。

答案 2 :(得分:1)

a -> Maybe a类型的函数是微不足道的。它只是Just。函数filterByType :: a -> Maybe b是不可能的。

这是因为一旦您编译了程序,ab就会消失。 Haskell中根本没有运行时类型信息。

但是,如另一个答案所述,你可以编写一个函数:

cast :: (Typeable a, Typeable b) => a -> Maybe b

您可以写这个的原因是因为约束Typeable a告诉编译器,无论何处调用此函数,都会传递由Typeable指定的运行时字典。这些是有用的操作,可以构建和拆除大量的Haskell类型。编译器对此非常聪明,并且可以为您使用该函数的几乎任何类型传递正确的字典。

但是,如果没有此运行时字典,则无法执行任何操作。没有Typeable的约束,你根本就没有得到运行时字典。

除此之外,如果你不介意我的询问,你究竟想要这个功能是什么?按类型过滤在Haskell中实际上并不实用,所以如果你试图这样做,你可能试图以错误的方式解决问题。