纯 Haskell Lambda 微积分中列表的函子性
Functoriality of List in Pure Haskell Lambda Calculus
我正在尝试使用 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
for List
出现。
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
的每个值,因为它受 forall
约束吗?
Haskell 的类型系统不够强大,无法像您那样编写 map
。改为这样写:
map f xs c n = xs (c . f) n
问题是,要使地图正常工作,您需要将 List a
类型中的量化类型变量 b
选择为 List b
(这是 "other"b
你用的,不是同类型变量)。将 forall
类型分配给类型变量需要间接性,GHC 不支持。
在这里,我尝试通过使用显式应用程序将 xs
调用为 xs @(List 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
一个可能的解决方案是将 List a
包装在 newtype
中,然后手动执行 wrapping/unwrapping。
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
和 unL
,但它们是相同的代码。
上面的 Joseph Sible 提出了一个更简单的解决方案,它不需要传递多态类型的值。
我正在尝试使用 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
for List
出现。
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
的每个值,因为它受 forall
约束吗?
Haskell 的类型系统不够强大,无法像您那样编写 map
。改为这样写:
map f xs c n = xs (c . f) n
问题是,要使地图正常工作,您需要将 List a
类型中的量化类型变量 b
选择为 List b
(这是 "other"b
你用的,不是同类型变量)。将 forall
类型分配给类型变量需要间接性,GHC 不支持。
在这里,我尝试通过使用显式应用程序将 xs
调用为 xs @(List 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
一个可能的解决方案是将 List a
包装在 newtype
中,然后手动执行 wrapping/unwrapping。
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
和 unL
,但它们是相同的代码。
上面的 Joseph Sible 提出了一个更简单的解决方案,它不需要传递多态类型的值。