无法从头开始实现自然数算术

时间:2017-03-08 17:41:32

标签: haskell

我经历过LYAH,但我觉得这不是Haskell的一个很好的介绍。我遇到了“对Haskell的温和介绍”,它推荐了Richard Bird的“使用Haskell进行功能编程简介”。那是我正在读的那本书。第3章创建一个数据类型Nat并用它实现基本算术。

这是我到目前为止编写的代码:

module Main where
import Prelude hiding ((^^))

data Nat = Zero | Succ Nat
        deriving (Eq, Ord, Show)
xx :: Nat -> Nat -> Nat
m `xx` Zero   = Zero
m `xx` Succ n = (m `xx` n) `add` m

(^^) :: Nat -> Nat -> Nat
m ^^ Zero   = Succ Zero
m ^^ Succ n = (m ^^ n) `xx` m

add :: Nat -> Nat -> Nat
m `add` Zero   = m
m `add` Succ n = Succ(m `add` n)

factsu :: Nat -> Nat
factsu Zero     = Succ Zero
factsu (Succ n) = Succ n `xx` factsu n

--Zero = 0

showNat :: Nat -> String
showNat Zero = "Zero"
showNat (Succ Zero) = "Succ Zero"
showNat (Succ (Succ n)) = "Succ (" ++ showNat (Succ n) ++ ")"

main :: IO ()
main = return ()

这就是:

factsu Zero
Succ Zero
it :: Nat

如何定义Succ和Zero?

1 个答案:

答案 0 :(得分:3)

  

但我希望Zero等于0

根本问题是“我希望Zero等于0”。一个字面上的读物可能是“我想要Zero == (0 :: Integer)”,但这是不可能的,因为Zero0 :: Integer有不同的类型 - 你的Zero实际上是它自己的东西。当然,没有什么可以阻止你定义它们之间相互转换的函数:

natToInteger :: Nat -> Integer
integerToNat :: Integer -> Maybe Nat

另一方面,如果您只想让GHCi将Zero打印为“0”......

GHCi> Zero
0

...您需要的只是一个自定义Show实例,因为karakfa和leftaroundabout建议使用in the comments。但是,这不会改变Zero实际上是什么;你只是改变它的显示方式。

最后,第三种可能性是你想为你的Nat使用数字文字语法:

GHCi> 0 + 2 :: Nat
2
it :: Nat

如果您给Nat Num个实例,那么这实际上是可行的。但这可能是一个坏主意,因为(-)会是部分的,negate没有明智的实现(顺便说一下,这也是我在签名中放置Maybe的原因上面的integerToNat。此外,就像Show的情况一样,添加Num实例并不会实质上改变Nat的内容 - 特别是在一天结束时数字文字语法只是语法。

(你可能会质疑我的意思是“基本上”,如果你认为事物的特点是你可以用它们做什么;但我会在我们太偏离之前停在这里。)