Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 某些带有Church数字的操作的类型签名声明_Haskell_Church Encoding - Fatal编程技术网

Haskell 某些带有Church数字的操作的类型签名声明

Haskell 某些带有Church数字的操作的类型签名声明,haskell,church-encoding,Haskell,Church Encoding,我试着在哈斯克尔实现教堂的数字。这是我的代码: -- Church numerals in Haskell. type Numeral a = (a -> a) -> (a -> a) churchSucc :: Numeral a -> Numeral a churchSucc n f = \x -> f (n f x) -- Operations with Church numerals. sum :: Numeral a -> Numeral a -

我试着在哈斯克尔实现教堂的数字。这是我的代码:

-- Church numerals in Haskell.
type Numeral a = (a -> a) -> (a -> a)

churchSucc :: Numeral a -> Numeral a
churchSucc n f = \x -> f (n f x)

-- Operations with Church numerals.
sum :: Numeral a -> Numeral a -> Numeral a
sum m n = m . churchSucc n

mult :: Numeral a -> Numeral a -> Numeral a
mult n m = n . m

-- Here comes the first problem
-- exp :: Numeral a -> Numeral a -> Numeral a
exp n m = m n

-- Convenience function to "numerify" a Church numeral.
add1 :: Integer -> Integer
add1 = (1 +)

numerify :: Numeral Integer -> Integer
numerify n = n add1 0

-- Here comes the second problem
toNumeral :: Integer -> Numeral Integer
toNumeral 0 = zero
toNumeral (x + 1) = churchSucc (toNumeral x)

我的问题来自指数运算。如果我声明
toNumeral
exp
的类型签名,则代码不会编译。但是,如果我对类型签名声明进行注释,则一切正常。对于
toNumeral
exp
的正确声明是什么?

原因
exp
不能按您的方式编写,因为它涉及将
数字作为参数传递给
数字。这需要有一个
数字(a->a)
,但您只有一个
数字a
。你可以这样写

exp :: Numeral a -> Numeral (a -> a) -> Numeral a
exp n m = m n
除了不应该使用像
x+1
这样的模式之外,我看不出
toNumeral
有什么问题

toNumeral :: Integer -> Numeral a -- No need to restrict it to Integer
toNumeral 0 = \f v -> v
toNumeral x
  | x > 0 = churchSucc $ toNumeral $ x - 1
  | otherwise = error "negative argument"
另外,由于
m,您的
sum
也有错误。Churchsuck n
m*(n+1)
,因此它应该是:

sum :: Numeral a -> Numeral a -> Numeral a
sum m n f x = m f $ n f x -- Repeat f, n times on x, and then m more times.
然而,教堂数字是适用于所有类型的函数。也就是说,
数字字符串
不应该与
数字整数
不同,因为
数字
不应该关心它使用的是什么类型。这是一个通用的量化:
numeric
是一个函数,对于所有类型的
a
(a->a)->(a->a)
,它是用
RankNTypes
编写的,作为所有a的
类型numeric=。(a->a)->(a->a)

这是有道理的:一个教堂数字是由它的函数参数被重复多少次来定义的
\f v->v
调用
f
0次,因此它是0,
\f v->f v
是1,以此类推。强制一个
数字
对所有
a
都起作用确保它只能这样做。但是,允许
数字
关心
f
v
的类型可以删除限制,并允许您编写
(\f v->“nope”)::数字字符串
,即使这显然不是
数字

我会把它写成

{-# LANGUAGE RankNTypes #-}

type Numeral = forall a. (a -> a) -> (a -> a)

_0 :: Numeral
_0 _ x = x
-- The numerals can be defined inductively, with base case 0 and inductive step churchSucc
-- Therefore, it helps to have a _0 constant lying around

churchSucc :: Numeral -> Numeral
churchSucc n f x = f (n f x) -- Cleaner without lambdas everywhere

sum :: Numeral -> Numeral -> Numeral
sum m n f x = m f $ n f x

mult :: Numeral -> Numeral -> Numeral
mult n m = n . m

exp :: Numeral -> Numeral -> Numeral
exp n m = m n

numerify :: Numeral -> Integer
numerify n = n (1 +) 0

toNumeral :: Integer -> Numeral
toNumeral 0 = _0
toNumeral x
  | x > 0 = churchSucc $ toNumeral $ x - 1
  | otherwise = error "negative argument"
取而代之的是,它看起来干净多了,而且不像原来那样容易遇到路障

演示:


您可以在GHCi中查找它们或编写
::
,并让编译器为您显示类型。当然,GHC将推断
exp::a->(a->b)->b
,如果您想将其与教堂数字的幂运算联系起来,这并没有多大帮助。这是正确的,但它足够普遍,很难看出它是如何符合预期的。对教堂数字使用单字可能会限制它们的适用性。我会考虑使用一个多类型<代码>类型数字= FALALL A。(a->a)->a->a
使用所需的扩展名。在某些情况下,由于非指示性类型,这会撞到墙。如果一个人计划在任何实际的事情上使用这样的代码,那么最好使用
newtypenumeric=numeric(对于所有的a.(a->a)->(a->a))
。当然,这个答案中的版本同样适用于演示/学习。这里有一堆我与之一起拼凑的东西:关于sum,我有两个版本,一个是你提到的版本,另一个是我发布的版本。我发布了第二个,因为它看起来更简洁,然而,我没有意识到它是错的。谢谢你指出这一点并给出答案。顺便说一句,我认为sum的正确版本(以及使用您提供的一些技巧)可能是:
sum2::numeric((a->a)->(a->a))->numeric a->numeric a sum2 m n=m church n
。我同意你的说法,因为你的版本看起来更简洁,而且教堂数字的概括性更强。干杯
main = do out "5:" _5
          out "2:" _2
          out "0:" _0
          out "5^0:" $ exp _5 _0
          out "5 + 2:" $ sum _5 _2
          out "5 * 2:" $ mult _5 _2
          out "5^2:" $ exp _5 _2
          out "2^5:" $ exp _2 _5
          out "(0^2)^5:" $ exp (exp _0 _2) _5
       where _2 = toNumeral 2
             _5 = toNumeral 5
             out :: String -> Numeral -> IO () -- Needed to coax the inferencer
             out str n = putStrLn $ str ++ "\t" ++ (show $ numerify n)