Fra*_*aus 1 haskell functional-programming
我正在攻读"功能编程入门"考试.这是我遇到的问题之一:
"以下数据类型用于表示一手牌:
data Suit = Hearts | Clubs | Diamonds | Spades
deriving Eq
data Rank = Numeric Int | Jack | Queen | King | Ace
deriving Eq
data Card = NormalCard Rank Suit | Joker
deriving Eq
Run Code Online (Sandbox Code Playgroud)
定义一个函数
countAces:: [Card] -> Int
countAces = undefined
Run Code Online (Sandbox Code Playgroud)
其中countAces返回给定手牌中的牌数或者是aces或jokers.例如,如果手中有三个A和两个笑话,答案将是五个."
所以我想我会这样写:
countAces:: [Card] -> Int
countAces [] = 0
countAces (c:cs) | c == (NormalCard Ace _) = 1 + countAces (cs)
| c == Joker = 1 + countAces (cs)
| otherwise = countAces (cs)
Run Code Online (Sandbox Code Playgroud)
但这不会编译,我已经明白我不能写c ==(NormalCard Ace _).但是,如果我将功能更改为:
countAces:: [Card] -> Int
countAces [] = 0
countAces (c : cs) = countCard c + countAces cs
where countCard Joker = 1
countCard (NormalCard Ace _) = 1
countCard _ = 0
Run Code Online (Sandbox Code Playgroud)
然后它的作品!所以我的问题是,为什么第一个版本不起作用?
这是错误:
* Found hole: _ :: Suit
* In the second argument of `NormalCard', namely `_'
In the second argument of `(==)', namely `(NormalCard Ace _)'
In the expression: c == (NormalCard Ace _)
* Relevant bindings include
cs :: [Card] (bound at exam.hs:96:14)
c :: Card (bound at exam.hs:96:12)
countAces :: [Card] -> Int (bound at exam.hs:95:1)
Valid substitutions include
Hearts :: Suit (defined at exam.hs:87:13)
Clubs :: Suit (defined at exam.hs:87:22)
Diamonds :: Suit (defined at exam.hs:87:30)
Spades :: Suit (defined at exam.hs:87:41)
undefined :: forall (a :: TYPE r).
GHC.Stack.Types.HasCallStack =>
a
(imported from `Prelude' at exam.hs:1:1
(and originally defined in `GHC.Err'))
Run Code Online (Sandbox Code Playgroud)
非常感谢任何花时间阅读本文的人.
在你的守卫中c == (NormalCard Ace _),你没有进行模式匹配; 你试图比较你没有指定的西装c的新值Card.该_是一个"洞",这是一种非值触发一个错误,但确定哪些类型的_应该有,这对于调试和开发非常有用.
要进行模式匹配,请使用显式case表达式:
countAces (c:cs) = case c of
(NormalCard Ace _) -> 1 + countAces cs
Joker -> 1 + countAces cs
otherwise -> countAces cs
Run Code Online (Sandbox Code Playgroud)
因为case是表达式而不是语句,所以可以重构它以减少重复:
countAces (c:cs) = countAces cs + case c of
(NormalCar Ace _) -> 1
Joker -> 0
otherwise -> 0
Run Code Online (Sandbox Code Playgroud)
它基本上概括了countCard您在第二次尝试中定义的功能.
这个问题更多的是关于你的意思是什么的心理模型,而不是关于Haskell本身(如果你问Haskell本身,那么答案是:"因为这就是语言是如何工作的").
所以我会尝试吸引你的想象力:
在第一种情况下,您有一个表达式,它将评估为True或False- 两者都是有效结果.您正在使用现有函数执行比较:(==).这个函数有两个值 - 你需要完全提供它们,没有漏洞 - 出于完全相同的原因,为什么你不能写(2 + _) * 10它并期望它评估一个数字.
在第二种情况下,您使用语言构造=.此构造不是返回值的函数.它用于构建定义.当你写作时a = 2,你不是在写一个可能是真或假的表达.您正在定义a来讲2.它将工作并永远是真的 - 或者不会编译.在这种情况下 - 你可以使用洞.当你写作时a _ = 2,你真的说:无论你申请什么,a你都会得到2.
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |