简体   繁体   English

我如何遍历一个 n 元素列表并对每个元素应用一个函数

[英]How do i iterate through an n element list and apply a function on each element

right player wins , the function returns 1, if the other side does its -1正确的玩家获胜,该函数返回 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

i need to evaluate the following with the truth table above.我需要使用上面的真值表评估以下内容。

evalBunch (x,y,z) = evalTurn x + evalTurn y + evalTurn z

evalMatch :: ([Symbol], [Symbol]) -> Outcome
evalMatch (x,y) = evalBunch (zip x y)

the test case presents 2 players with each turn's result , summed up测试用例向 2 个玩家展示每轮的结果,总结

evalMatch ([1,1,1], [0,0,0]) == -3

First, consider using more domain-centered data types for your values, instead of just using ints with special meanings.首先,考虑为您的值使用更多以领域为中心的数据类型,而不是仅使用具有特殊含义的整数。 eg it looks like here you're playing Rock Paper Scissors, so you'd have a better time with something like例如,看起来你在这里玩的是剪刀石头布,所以你会玩得更开心

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
-- ...

As is, you've accidentally repeated a case in your evalTurn : you have that evalTurn 0 1 = 1 , but also evalTurn 0 1 = -1 . evalTurn ,您不小心在evalTurn重复了一个案例:您有evalTurn 0 1 = 1 ,但也有evalTurn 0 1 = -1 This would be easier to spot if you used richer domain models.如果您使用更丰富的域模型,这将更容易发现。 Or, if you want to stick with your integers, there is actually a shortcut using modular arithmetic:或者,如果你想坚持使用整数,实际上有一个使用模运算的捷径:

evalTurn x y = case (y - x) `mod` 3 of
  0 -> 0
  1 -> 1
  2 -> -1

As to your actual question there are a number of problems before you can get to what you're trying to fix.至于你的实际问题,在你得到你想要解决的问题之前,有很多问题。 evalTurn , evalBunch , and evalMatch all disagree on what the type of Symbol should be, and how many arguments evalTurn actually takes. evalTurnevalBunchevalMatch在 Symbol 应该是什么类型以及evalTurn实际需要多少个参数上都存在分歧。 Does it make sense to call evalTurn with one argument, as evalBunch does?evalBunch那样用一个参数调用evalTurn是否有意义? Surely not.当然不是。

My first suggestion would be to forget this evalBunch function completely, and write evalMatch in terms of evalTurn directly.我的第一个建议是要忘记这evalBunch完全功能,并写evalMatch来讲evalTurn直接。 It would probably be good practice for you to write it recursively by hand, rather than using fancy zips, curries, and function composition.手动递归编写它可能是一个好习惯,而不是使用花哨的 zips、curries 和函数组合。


Another thing you could do, if you like the richer domain models I suggsted but don't want to write out all 9 cases (or 7 if you shortcut the x == y cases), is to instead define "does X beat Y" as a boolean primitive, and then build upon that to decide the more complicated question of who wins a match:如果您喜欢我建议的更丰富的域模型,但不想写出所有 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

It's not really much shorter, perhaps even longer.它并没有真正短得多,甚至可能更长。 But it avoided repetition, and now as a nice side benefit the program "knows" a little more about Symbols outside the context of evalTurn , which may prove useful somehow in another part of the program.但是它避免了重复,现在作为一个好的方面好处是程序“知道”更多关于evalTurn上下文之外的符号,这可能在程序的另一部分以某种方式证明是有用的。 For example, you could use this to draw a tutorial diagram of what beats what.例如,您可以使用它来绘制什么胜于什么的教程图。

Keeping a little to the way in which the initial problem was presented, I suggest the following simplifications:保持一点最初问题的呈现方式,我建议进行以下简化:

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

So, doesn't this function solve your use case?那么,这个功能不能解决您的用例吗?

Prelude> evalBunch [(1, 0), (1,0), (1,0)] 
Prelude> -3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM