纯Haskell-Lambda演算中列表的函数性
我试图用Haskell在纯lambda演算中实现各种各样的东西。 一切正常纯Haskell-Lambda演算中列表的函数性,haskell,lambda,functor,lambda-calculus,parametric-polymorphism,Haskell,Lambda,Functor,Lambda Calculus,Parametric Polymorphism,我试图用Haskell在纯lambda演算中实现各种各样的东西。 一切正常 {-# LANGUAGE RankNTypes #-} type List a = forall b. (a -> b -> b) -> b -> b empty :: List a empty = const id cons :: a -> List a -> List a cons x xs f y = f x (xs f y) 直到列表的映射出现 map :: (a -&
{-# LANGUAGE RankNTypes #-}
type List a = forall b. (a -> b -> b) -> b -> b
empty :: List a
empty = const id
cons :: a -> List a -> List a
cons x xs f y = f x (xs f y)
直到列表的映射
出现
map :: (a -> b) -> List a -> List b
map f xs = xs (cons . f) empty
导致以下错误消息:
• Couldn't match type ‘List b’ with ‘(b -> b1 -> b1) -> b1 -> b1’
Expected type: b
-> ((b -> b1 -> b1) -> b1 -> b1) -> (b -> b1 -> b1) -> b1 -> b1
Actual type: b -> List b -> List b
• In the first argument of ‘(.)’, namely ‘cons’
In the first argument of ‘xs’, namely ‘(cons . f)’
In the expression: xs (cons . f) empty
• Relevant bindings include
f :: a -> b (bound at Basic.hs:12:5)
map :: (a -> b) -> List a -> List b (bound at Basic.hs:12:1)
为什么cons
有效而map
无效?List
的每一个实例不应该都适用于b
的每一个值吗,因为它受的所有的约束?哈斯克尔的类型系统不够强大,无法像您那样编写映射。改为这样写:
map f xs c n = xs (c . f) n
问题是,要使映射正常工作,您需要在列表a
类型中选择量化类型变量b
,将其设置为列表b
(这是您使用的“其他”b
,它不是相同的类型变量)。将forall
类型分配给类型变量需要不可指示性,GHC不支持这种不可指示性
在这里,我试图通过使用explicit类型的应用程序调用xs
asxs@(列表b)…
来强制实例化b
map :: forall a b. (a->b) -> List a -> List b
map f xs = xs @(List b) (cons . f) empty
error:
* Illegal polymorphic type: List b
GHC doesn't yet support impredicative polymorphism
* In the expression: xs @(List b) (cons . f) empty
In an equation for `map': map f xs = xs @(List b) (cons . f) empty
一种可能的解决方案是将列表
包装在新类型
中,并手动执行包装/展开
newtype L a = L { unL :: List a }
map :: forall a b. (a->b) -> List a -> List b
map f xs = unL $ xs @(L b) (\y ys -> L (cons (f y) (unL ys))) (L empty)
代码中充斥着L
s和unL
s,但它是同一个代码
上面Joseph Sible提出了一个更简单的解决方案,它不需要传递多态类型的值。相关:要正确地键入术语,您需要使用多态类型实例化()
的一个类型变量。如果您开始对无法预测可以和不能推断的内容感到恼火,一个好的解决方案是使List
anewtype List a=List{unList::forall b.(a->b->b)->b->b}
。您必须明确包装和展开,但这样做会使事情变得更简单、更可预测。如果您打开ImpredicativeTypes
扩展名,您对map
的第一个定义实际上会起作用。@Josephyble很有趣。不过,该扩展目前的状态很糟糕。通常,GHC错误消息建议您在尝试使用扩展时打开它,但在这种情况下,错误会假装扩展不存在。Haskell并不真正支持不确定性这一事实回答了我的问题。我知道newtype
在实践中是如何使用的,我想看看type
可以用RankNTypes
推到什么程度,因为它会产生有趣的概括,比如[]
的返回id
,无和Curch编码中的0
。