【问题标题】:Using the y combinator in haskell在 haskell 中使用 y 组合器
【发布时间】:2016-08-18 00:25:25
【问题描述】:

我是 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 组合子的定义,但没有说明如何使用它。

【问题讨论】:

  • Y Combinator in Haskell的可能重复
  • @chepner 为什么是重复的?这个问题(我链接到)提供了 y 组合器的定义,但没有解释如何使用它。
  • @dimid 建议的副本见this answer。你不能输入 Y 组合符。
  • @chepner 那么,显然 this 不会进行类型检查和工作吗? :)
  • @chepner 是的,我知道您需要使用某些技巧,例如 unsafeCoerce,但这不是问题所在。问题是这个问题提供了 y 组合子的定义,但没有解释如何使用它,这就是我问这个问题的原因。

标签: haskell lambda-calculus combinators


【解决方案1】:

我引入了函数add(显然添加了两个教会数字)来简化ch_sum的定义:

add :: Chur -> Chur -> Chur
add (Chr cn1) (Chr cn2) = Chr (\h -> cn1 h . cn2 h)

要使用定点组合器创建递归函数,您需要将其编写为普通递归函数(使用具有递归的语言),但作为最后一步添加显式 “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

【讨论】:

  • 谢谢,我认为使用后继定义加法更清晰(至少对我而言):ch_add (Chr cn1) (Chr cn2) = cn1 suc (Chr cn2)
  • 是的,你是对的。这将是一种更简洁的方法(从几个角度来看):一旦我们定义了 zersuc(也许还有其他一些“原始”,比如 Church 对,......),我们不应该使用任何东西,除了那些构建其他算术函数。顺便说一句,add (Chr cn1) arg2 = cn1 suc arg2 是编写加法函数的另一种方式(原则上不是,它只是避免了第二个参数的展开/折叠)。
  • 另外,可以在没有RankNTypes 扩展名的情况下实现 Church 数字,但是您必须使用类似于我的答案中的版本的实现,否则它不会进行类型检查。跨度>
  • 有趣,你的意思是这样的实现吗? stackoverflow.com/a/6464164/165753
  • 是的,但是更高的排名可以让你更有表现力。
猜你喜欢
  • 2011-05-15
  • 2012-01-08
  • 1970-01-01
  • 2014-05-30
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多