haskell - 在 Haskell 中实现 Smullyan 的算术鸟

标签 haskell combinators combinatory-logic

在搜索 Raymond Smullyan 的 To Mock a Mockingbird 的信息时,我偶然发现了 Stephen Tetley's Haskell code for the basic combinators .我认为这是一个有趣的想法,并决定使用这些组合器来实现 To Mock a Mockingbird 第 24 章中的“可以做算术的鸟”。我已经定义了真、假、继任者、前任和零校验组合器,以及将组合 bool 值更改为 Haskell bool 值的函数,反之亦然。但是当我尝试创建一个接受组合数字并返回整数的函数时,我一直遇到问题。我想知道如何使这个功能工作。这是我到目前为止所得到的:

-- | The first 7 combinators below are from Stephen Tetley's Data.Aviary.Birds
-- | (http://hackage.haskell.org/package/data-aviary-0.2.3/docs/Data-Aviary-Birds.html),
-- | with minor modifications.


-- | S combinator - starling. 
-- Haskell: Applicative\'s @(\<*\>)@ on functions.
-- Not interdefined.
st :: (a -> b -> c) -> (a -> b) -> a -> c
st f g x = f x (g x)

-- | K combinator - kestrel - Haskell 'const'.
-- Corresponds to the encoding of @true@ in the lambda calculus.
-- Not interdefined.
ke :: a -> b -> a
ke a _b = a 

-- | I combinator - identity bird / idiot bird - Haskell 'id'.
id' :: a -> a 
id' = st ke ke 

-- | B combinator - bluebird - Haskell ('.').
bl :: (b -> c) -> (a -> b) -> a -> c
bl = st (ke st) ke

-- | C combinator - cardinal - Haskell 'flip'.
ca :: (a -> b -> c) -> b -> a -> c
ca = st(st(ke st)(st(ke ke)st))(ke ke)

-- | T combinator - thrush.
-- Haskell @(\#)@ in Peter Thiemann\'s Wash, reverse application.
th :: a -> (a -> b) -> b
th = ca id'

-- | V combinator - vireo.
vr :: a -> b -> (a -> b -> d) -> d
vr = bl ca th




-- | The code I added begins here. 




-- | Truth combinator. Functionally superfluous since it can  
-- | be replaced with the kestrel. Added for legibility only.
tr :: a -> b -> a
tr = ke

-- | Falsity combinator.
fs :: a -> b -> b
fs = ke id'

-- | Successor combinator.
sc :: a -> ((b -> c -> c) -> a -> d) -> d
sc = vr fs 

-- | Predecessor combinator.
pd :: ((((a -> a) -> b) -> b) -> c) -> c
pd = th (th id')

-- | Zerocheck combinator.
zc :: ((a -> b -> a) -> c) -> c
zc = th ke



-- | Below are 2 functions for changing combinatory booleans 
-- | to Haskell booleans and vice versa. They work fine as 
-- | far as I can tell, but I'm not very confident about 
-- | their type declarations. I just took the types 
-- | automatically inferred by Haskell.

-- | Combinatory boolean to Haskell boolean.
cbhb :: (Bool -> Bool -> Bool) -> Bool
cbhb cb  = cb True False

-- | Haskell boolean to combinatory boolean.
hbcb :: Bool -> a -> a -> a
hbcb hb | hb     = tr
        | not hb = fs




-- | Combinatory number to Haskell number. 
-- | This is the problematic function that I'd like to implement. 
-- | I think the function is logically correct, but I have no clue
-- | what its type would be. When I try to load it in Hugs it 
-- | gives me a "unification would give infinite type" error. 
cnhn cn | cbhb (zc cn) = 0
        | otherwise    = 1 + cnhn (pd cn)

这是我对代码问题的粗略猜测:“cnhn”函数将任何组合数字作为参数。但是不同的组合数有不同的类型,比如

零)id'​​::a -> a

一)vr(ke id')id'::((a -> b -> b) -> (c -> c) -> d) -> d

二)vr(ke id')(vr(ke id')id')::((a -> b -> b) -> (((c -> d -> d) -> (e -> e ) -> f) -> f) -> g) -> g

等等。因此,将任何组合数作为参数的函数必须能够采用无限多种类型的参数。但是 Haskell 不允许这样的功能。

简而言之,这是我的 3 个主要问题:

1) 'cnhn' 函数有什么问题? (我上面的猜测正确吗?)

2)可以修复吗?

3)如果不是,我可以使用什么其他语言来实现 Smullyan 的算术鸟?

感谢您阅读一个很长的问题。

最佳答案

似乎后继组合器不太正确。这是 Haskell 中 Church 算术的编码,unchurch函数是什么cnhn (我猜是教堂编号到 Haskell 编号?)正在尝试实现。

tr :: a -> b -> a
tr x y = x

fl :: a -> b -> b
fl x y = y

succ :: ((a -> b) -> c -> a) -> (a -> b) -> c -> b
succ n f x = f (n f x)

unbool :: (Bool -> Bool -> t) -> t
unbool n = n True False

unchurch :: ((Int -> Int) -> Int -> a) -> a
unchurch n = n (\i -> i + 1) 0

church :: Int -> (a -> a) -> a ->a
church n =
  if n == 0
  then zero
  else \f x -> f (church (n-1) f x)

zero :: a -> b -> b
zero = fl

one :: (a -> a) -> a -> a
one = succ zero

two :: (a -> a) -> a -> a
two = succ one

ten :: (a -> a) -> a -> a
ten = succ (succ (succ (succ (succ (succ (succ (succ (succ (succ zero)))))))))

main = do
  print (unchurch ten)
  print (unchurch (church 42))

So a function that takes any combinatory number as an argument must be able to take infinitely many types of arguments. But Haskell doesn't allow such functions.



啊,但它确实是因为 Haskell 允许参数多态性。如果您查看数字的编码,它们都具有签名((a -> a) -> a -> a),因此采用教堂编号的函数的参数只需要使其第一个参数将其第一个参数的类型变量与对教堂编号进行编码的函数统一起来.

例如,我们还可以定义一个乘法运算,它实际上只是一个高阶函数,它需要两个教堂编号并将它们相乘。这适用于任何两个教会号码。
mult :: (a -> b) -> (c -> a) -> c -> b
mult m n f = m (n f)

test :: (a -> a) -> a -> a
test = mult ten ten

main = print (unchurch test) -- 100

关于haskell - 在 Haskell 中实现 Smullyan 的算术鸟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21561788/

相关文章:

function - 将表单定义为函数名称?

haskell - 找到 Haskell 函数 f, g 使得 f g = f 。 G

haskell - 在 SKI 组合器中表达 XOR

scala - 在函数列表上折叠 flatMap/bind(也就是命名组合器!)

functional-programming - 什么是 Y 组合器?

haskell - Haskell 中的短路 (&&)

haskell - 自然数作为递归数据类型

haskell - Intero 始终安装独立的 GHC

exception - Haskell:处理类型和异常