Haskell考试复习:非递归实现scoreHand函数求助
如何实现Haskell中scoreHand函数的非递归版本?
嘿,你的递归版本逻辑很清晰嘛!既然已经搞定了递归实现,那非递归版本其实可以借助Haskell的标准库函数或者列表推导式来轻松完成,完全不用自己写递归逻辑~
先回顾一下你已经完成的递归代码(方便对照):
import Data.Char type PlayingCardValue = Char scoreHand :: [PlayingCardValue] -> Int scoreHand [] = 0 scoreHand (x:xs) = if x > '1' && x < '9' then digitToInt x + scoreHand (xs) else if x == 'T' || x == 'J' || x == 'Q' || x == 'K' then 10 + scoreHand (xs) else if x == 'A' then 11 + scoreHand (xs) else 0 + scoreHand (xs)
方案1:用map+sum的函数组合实现
这个版本利用函数组合把“转换每个牌面到分值”和“求和”两个步骤结合起来,代码更简洁:
import Data.Char type PlayingCardValue = Char scoreHand :: [PlayingCardValue] -> Int scoreHand = sum . map cardToValue where -- 定义单个牌面到分值的转换函数 cardToValue :: PlayingCardValue -> Int cardToValue c | c `elem` ['2'..'9'] = digitToInt c -- 2-9直接转对应数字 | c `elem` ['T','J','Q','K'] = 10 -- 花牌都是10分 | c == 'A' = 11 -- A是11分 | otherwise = 0 -- 无效牌面得0分
逻辑解释:
map cardToValue会遍历输入的手牌列表,把每个PlayingCardValue转换成对应的分值,生成一个整数列表;sum则把这个整数列表里的所有值加起来,得到总分;- 用
.做函数组合,相当于scoreHand cards = sum (map cardToValue cards),只是写法更符合Haskell的函数式风格。
方案2:用列表推导式实现
如果你更习惯列表推导式的写法,也可以这样写,逻辑和上面完全一致:
import Data.Char type PlayingCardValue = Char scoreHand :: [PlayingCardValue] -> Int scoreHand cards = sum [ getValue c | c <- cards ] where getValue c | c `elem` ['2'..'9'] = digitToInt c | c `elem` ['T','J','Q','K'] = 10 | c == 'A' = 11 | otherwise = 0
逻辑解释:
- 列表推导式
[ getValue c | c <- cards ]会逐个取出cards里的每个牌面c,计算它的分值,最终生成一个分值列表; - 再用
sum对这个列表求和,就得到了手牌的总分。
这两个非递归版本都和你原来的递归版本逻辑完全对齐,包括对无效牌面返回0分的处理,放心用就好!
内容的提问来源于stack exchange,提问作者Stefani Dimitrova
相关产品推荐
相关产品推荐

