纯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 -&

我试图用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 -> 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
as
xs@(列表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
a
newtype List a=List{unList::forall b.(a->b->b)->b->b}
。您必须明确包装和展开,但这样做会使事情变得更简单、更可预测。如果您打开
ImpredicativeTypes
扩展名,您对
map
的第一个定义实际上会起作用。@Josephyble很有趣。不过,该扩展目前的状态很糟糕。通常,GHC错误消息建议您在尝试使用扩展时打开它,但在这种情况下,错误会假装扩展不存在。Haskell并不真正支持不确定性这一事实回答了我的问题。我知道
newtype
在实践中是如何使用的,我想看看
type
可以用
RankNTypes
推到什么程度,因为它会产生有趣的概括,比如
[]
返回id
和Curch编码中的
0