有没有办法让haskell擦除类型信息/向下转换为多态值?
在示例中,我有一个盒装类型T,它可以包含Int或Char 我想编写一个函数来提取这个值而不知道它是什么类型。
{#- LANGUAGE RankNTypes -#}
data T = I Int | C Char
-- This is not working because GHC cannot bind "a"
-- with specific type Int and Char at the same time.
-- I just want a polymorphic value back ;(
getValue :: T -> (forall a. a)
getValue (I val) = val
getValue (C val) = val
-- This on the other hand works, because the function
-- is local to the pattern matching expression
onValue :: T -> (forall a. a -> a) -> T
onValue (I val) f = I $ f val
onValue (C val) f = C $ f val
有没有办法编写一个可以在不强制输入类型的情况下提取此值的函数?
像第一个一样的getValue函数?
如果不够明确,请告诉我。
所以问题是愚蠢的,因为AndrewC(在评论中)和YellPika指出。无限型没有意义。
学家Abrahamson为我要找的东西提供了解释,所以我把他的答案作为解决方案。
P.S:我不想使用GADT,因为我不想每次都使用新类型。
答案 0 :(得分:6)
您可能想要的不是返回值(forall a . a)
,因为它在几个方面都是错误的。例如,您没有任何值,而只是两个中的一个。对于两个,这种类型不能存在于行为良好的程序中:它对应于无限循环和异常的类型,例如,底部。
最后,这种类型允许拥有它的人做出选择以更具体地实例化它。因为你将它交给你的函数的调用者,这意味着他们可以选择你拥有的Int或Char中的哪一个。显然这没有意义。
相反,您最想要的是向您的功能用户提出要求:“无论此类型是什么,您都必须工作。”
foo :: (forall a . a -> r) -> (T -> r)
foo f (I i) = f i
foo f (C c) = f c
您会发现此功能与以下
非常相似bar :: r -> T -> r
bar x (I _) = x
bar x (C _) = x
换句话说,如果你强迫你的功能的消费者忽略所有类型信息,那么,实际上什么都没有留下:例如一个恒定的功能。
答案 1 :(得分:5)
您可以使用GADTs
:
{-# LANGUAGE GADTs #-}
data T a where
I :: Int -> T Int
C :: Char -> T Char
getValue :: T a -> a
getValue (I i) = i
getValue (C c) = c
答案 2 :(得分:3)
如果您打开ExistentialTypes
,则可以写:
data Anything = forall a. Anything a
getValue :: T -> Anything
getValue (I val) = Anything val
getValue (C val) = Anything val
然而,这是无用的。假设我们在Anything
上模式匹配:
doSomethingWith (Anything x) = ?
除了x
以外,我们不知道任何事情...(好吧,甚至不是 - 它可能是undefined
)。没有类型信息,因此我们无法对其进行任何操作。