在 haskell 中使用 y 组合器
Using the y combinator in haskell
我是 haskell 的初学者,正在尝试实现自然数的 Church 编码,如 this guide 中所述。
我使用了 this answer 中的 y 组合器的定义,但不确定如何应用它。
我想在 lambda 演算中实现一个简单的函数,它计算 [1..n] 的总和,如 here 所示。
{-# LANGUAGE RankNTypes #-}
import Unsafe.Coerce
y :: (a -> a) -> a
y = \f -> (\x -> f (unsafeCoerce x x)) (\x -> f (unsafeCoerce x x))
true = (\x y -> x)
false = (\x y -> y)
newtype Chur = Chr (forall a. (a -> a) -> (a -> a))
zer :: Chur
zer = Chr (\x y -> y)
suc :: Chur -> Chur
suc (Chr cn) = Chr (\h -> cn h . h)
ci :: Chur -> Integer
ci (Chr cn) = cn (+ 1) 0
ic :: Integer -> Chur
ic 0 = zer
ic n = suc $ ic (n - 1)
-- church pair
type Chp = (Chur -> Chur -> Chur) -> Chur
pair :: Chur -> Chur -> Chp
pair (Chr x) (Chr y) f = f (Chr x) (Chr y)
ch_fst :: Chp -> Chur
ch_fst p = p true
ch_snd :: Chp -> Chur
ch_snd p = p false
next_pair :: Chp -> Chp
next_pair = (\p x -> x (suc (p true)) (p true))
n_pair :: Chur -> Chp -> Chp
n_pair (Chr n) p = n next_pair p
p0 = pair zer zer
pre :: Chur -> Chur
pre (Chr cn) = ch_snd $ n_pair (Chr cn) p0
iszero :: Chur -> (a->a->a)
iszero (Chr cn) = cn (\h -> false) true
unchr :: Chur -> ((a -> a) -> (a -> a))
unchr (Chr cn) = cn
ch_sum (Chr cn) = (\r -> iszero (Chr cn) zer (cn suc (r (pre (Chr cn)))))
到目前为止一切顺利,但我如何将 y
应用到 sum
?
例如
n3 = ic 3
y ch_sum n3
导致类型不匹配:
<interactive>:168:3:
Couldn't match type ‘(Chur -> Chur) -> Chur’ with ‘Chur’
Expected type: ((Chur -> Chur) -> Chur) -> (Chur -> Chur) -> Chur
Actual type: Chur -> (Chur -> Chur) -> Chur
In the first argument of ‘y’, namely ‘ch_sum’
In the expression: y ch_sum n3
<interactive>:168:10:
Couldn't match expected type ‘Chur -> Chur’ with actual type ‘Chur’
In the second argument of ‘y’, namely ‘n3’
In the expression: y ch_sum n3
Y Combinator in Haskell 提供了 y 组合子的定义,但没有解释如何使用它。
我引入了函数 add
(显然添加了两个教会数字)来简化 ch_sum
的定义:
add :: Chur -> Chur -> Chur
add (Chr cn1) (Chr cn2) = Chr (\h -> cn1 h . cn2 h)
要使用定点组合器创建递归函数,您需要将其编写为普通递归函数(使用递归语言),但作为最后一步添加 explicit "self" 参数作为第一个函数的参数(在本例中为 r
),而不是递归调用,您只需调用 "self"(r
)。所以ch_sum
可以写成
ch_sum :: (Chur -> Chur) -> Chur -> Chur
ch_sum = \r n -> iszero n zer $ add n (r $ pre n)
ghci 中的一些测试:
λ> let n3 = ic 3
λ> ci (y ch_sum n3)
6
λ> let n10 = ic 10
λ> ci (y ch_sum n10)
55
我是 haskell 的初学者,正在尝试实现自然数的 Church 编码,如 this guide 中所述。 我使用了 this answer 中的 y 组合器的定义,但不确定如何应用它。
我想在 lambda 演算中实现一个简单的函数,它计算 [1..n] 的总和,如 here 所示。
{-# LANGUAGE RankNTypes #-}
import Unsafe.Coerce
y :: (a -> a) -> a
y = \f -> (\x -> f (unsafeCoerce x x)) (\x -> f (unsafeCoerce x x))
true = (\x y -> x)
false = (\x y -> y)
newtype Chur = Chr (forall a. (a -> a) -> (a -> a))
zer :: Chur
zer = Chr (\x y -> y)
suc :: Chur -> Chur
suc (Chr cn) = Chr (\h -> cn h . h)
ci :: Chur -> Integer
ci (Chr cn) = cn (+ 1) 0
ic :: Integer -> Chur
ic 0 = zer
ic n = suc $ ic (n - 1)
-- church pair
type Chp = (Chur -> Chur -> Chur) -> Chur
pair :: Chur -> Chur -> Chp
pair (Chr x) (Chr y) f = f (Chr x) (Chr y)
ch_fst :: Chp -> Chur
ch_fst p = p true
ch_snd :: Chp -> Chur
ch_snd p = p false
next_pair :: Chp -> Chp
next_pair = (\p x -> x (suc (p true)) (p true))
n_pair :: Chur -> Chp -> Chp
n_pair (Chr n) p = n next_pair p
p0 = pair zer zer
pre :: Chur -> Chur
pre (Chr cn) = ch_snd $ n_pair (Chr cn) p0
iszero :: Chur -> (a->a->a)
iszero (Chr cn) = cn (\h -> false) true
unchr :: Chur -> ((a -> a) -> (a -> a))
unchr (Chr cn) = cn
ch_sum (Chr cn) = (\r -> iszero (Chr cn) zer (cn suc (r (pre (Chr cn)))))
到目前为止一切顺利,但我如何将 y
应用到 sum
?
例如
n3 = ic 3
y ch_sum n3
导致类型不匹配:
<interactive>:168:3:
Couldn't match type ‘(Chur -> Chur) -> Chur’ with ‘Chur’
Expected type: ((Chur -> Chur) -> Chur) -> (Chur -> Chur) -> Chur
Actual type: Chur -> (Chur -> Chur) -> Chur
In the first argument of ‘y’, namely ‘ch_sum’
In the expression: y ch_sum n3
<interactive>:168:10:
Couldn't match expected type ‘Chur -> Chur’ with actual type ‘Chur’
In the second argument of ‘y’, namely ‘n3’
In the expression: y ch_sum n3
Y Combinator in Haskell 提供了 y 组合子的定义,但没有解释如何使用它。
我引入了函数 add
(显然添加了两个教会数字)来简化 ch_sum
的定义:
add :: Chur -> Chur -> Chur
add (Chr cn1) (Chr cn2) = Chr (\h -> cn1 h . cn2 h)
要使用定点组合器创建递归函数,您需要将其编写为普通递归函数(使用递归语言),但作为最后一步添加 explicit "self" 参数作为第一个函数的参数(在本例中为 r
),而不是递归调用,您只需调用 "self"(r
)。所以ch_sum
可以写成
ch_sum :: (Chur -> Chur) -> Chur -> Chur
ch_sum = \r n -> iszero n zer $ add n (r $ pre n)
ghci 中的一些测试:
λ> let n3 = ic 3
λ> ci (y ch_sum n3)
6
λ> let n10 = ic 10
λ> ci (y ch_sum n10)
55