RankNTypes和模式匹配

Erè*_*èbe 0 polymorphism haskell higher-rank-types

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
Run Code Online (Sandbox Code Playgroud)

有没有办法编写一个函数,可以提取这个值而不必在最后强制类型?

像第一个一样的getValue函数?

如果不够清楚,请告诉我.

回答

所以问题是愚蠢的,因为AndrewC(在评论中)和YellPika指出.无限型没有意义.

J. Abrahamson提供了我正在寻找的解释,所以我把他的答案作为解决方案.

PS:我不想使用GADT,因为我不想每次都使用新类型.

J. *_*son 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
Run Code Online (Sandbox Code Playgroud)

您会发现此功能与以下内容非常相似

bar :: r -> T -> r
bar x (I _) = x
bar x (C _) = x
Run Code Online (Sandbox Code Playgroud)

换句话说,如果你强迫你的函数的使用者忽略所有类型信息,那么,实际上什么都没有留下:例如一个常数函数.


use*_*465 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
Run Code Online (Sandbox Code Playgroud)