正确的玩家获胜,如果对方执行-1,则该函数返回1
evalTurn :: Symbol -> Symbol -> Outcome
evalTurn x y | x == y = 0
evalTurn 0 1 = 1
evalTurn 0 2 = -1
evalTurn 1 2 = 1
evalTurn 0 1 = -1
evalTurn 2 0 = 1
evalTurn 2 1 = -1
evalTurn 1 0 = -1
我需要使用上面的真值表评估以下内容。
evalBunch (x,y,z) = evalTurn x + evalTurn y + evalTurn z
evalMatch :: ([Symbol], [Symbol]) -> Outcome
evalMatch (x,y) = evalBunch (zip x y)
测试用例向每个回合的2位玩家展示结果,总结
evalMatch ([1,1,1], [0,0,0]) == -3
答案 0 :(得分:5)
首先,考虑为您的值使用更多以域为中心的数据类型,而不是仅使用具有特殊含义的整数。例如看起来您在这里玩的是剪刀石头布,所以您会喜欢上这样的东西
data Symbol = Rock | Paper | Scissors deriving Eq
data Outcome = Win | Lose | Tie
evalTurn :: Symbol -> Symbol -> Outcome
evalTurn x y | x == y = Tie
evalTurn Rock Paper = Lose
-- ...
照原样,您不小心在evalTurn
中重复了一个案例:既有evalTurn 0 1 = 1
,又有evalTurn 0 1 = -1
。如果您使用更丰富的域模型,这将更容易发现。或者,如果您想坚持使用整数,则实际上是使用模块化算法的捷径:
evalTurn x y = case (y - x) `mod` 3 of
0 -> 0
1 -> 1
2 -> -1
关于您的实际问题,在您要尝试解决的问题之前,存在许多问题。 evalTurn
,evalBunch
和evalMatch
在符号类型应该是什么以及evalTurn
实际需要多少个参数上都存在分歧。像evalTurn
那样用一个参数调用evalBunch
是否有意义?当然不会。
我的第一个建议是完全忘记此evalBunch
函数,而直接用evalMatch
来写evalTurn
。对您来说,最好递归地手工编写它,而不要使用花哨的zip,咖喱和函数组合。
如果您喜欢我建议的功能更丰富的域模型,但又不想写出全部9种情况(如果您简化x == y
用例,则是7种),您可以做的另一件事是定义“确实X击败Y”作为布尔值原语,然后以此为基础来决定谁赢得比赛的更复杂问题:
beats :: Symbol -> Symbol -> Bool
Rock `beats` Scissors = True
Scissors `beats` Paper = True
Paper `beats` Rock = True
_ `beats` _ = False
evalTurn :: Symbol -> Symbol -> Outcome
evalTurn x y | x `beats` y = Win
| y `beats` x = Lose
| otherwise = Tie
它并没有真正缩短,甚至更长。但是它避免了重复,并且作为一个好的好处,该程序现在在evalTurn
上下文以外的地方“了解”了一些有关Symbols的更多知识,这可能在程序的另一部分中被证明是有用的。例如,您可以使用它来画出什么胜过什么的教程图。
答案 1 :(得分:0)
稍微介绍一下最初出现问题的方式,我建议进行以下简化:
type Symbol = Int
type Outcome = Int
evalTurn :: (Symbol, Symbol) -> Outcome
evalTurn (x, y)
| (x == y) = 0
| (x == 0 && y == 1) = 1
| (x == 0 && y == 2) = -1
| (x == 1 && y == 2) = 1
| (x == 2 && y == 0) = 1
| (x == 2 && y == 1) = -1
| (x == 1 && y == 0) = -1
evalBunch :: (Foldable t, Functor t) => t (Symbol, Symbol) -> Outcome
evalBunch v = sum $ fmap evalTurn v
--Pointfree style is more elegant
--evalBunch = sum . fmap evalTurn
那么,这个功能不能解决您的用例吗?
Prelude> evalBunch [(1, 0), (1,0), (1,0)]
Prelude> -3