我经历过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?
答案 0 :(得分:3)
但我希望Zero等于0
根本问题是“我希望Zero
等于0
”。一个字面上的读物可能是“我想要Zero == (0 :: Integer)
”,但这是不可能的,因为Zero
和0 :: 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
的内容 - 特别是在一天结束时数字文字语法只是语法。
(你可能会质疑我的意思是“基本上”,如果你认为事物的特点是你可以用它们做什么;但我会在我们太偏离之前停在这里。)