有人可以用我的 Haskell 代码诊断问题吗?

Luc*_*cas 1 iteration recursion haskell if-statement list

我觉得我从根本上误解了 Haskell 的编写方式。我的代码旨在用作 Othello 游戏的原始 AI 的评估函数。本质上,我希望我的代码循环遍历一个棋子列表,每个棋子由一个由位置(Int,Int)和一个 Col(颜色,黑色或白色)组成的元组表示,并给出一个预期的移动,确定移动的好坏是。

我判断一个举动的价值的方式是基于几个因素:

  • 板上是否有一块与预期位置相同颜色的直线?
  • 如果前面的要求是真的,那两块之间有多少相反颜色的块?

由于 Haskell 没有循环结构,因此我似乎需要递归地实现它,因此我的代码如下:

eval :: Position -> [(Position, Col)] -> Col -> GameState -> Int -> Int
eval move pieces moveColour gameState score = do
                                                let moveX = fst move
                                                let moveY = snd move
                                                let piece = head(pieces)
                                                let pieceColour = snd piece
                                                let pieceX = fst fst piece
                                                let pieceY = snd fst piece
                                                if (moveColour == pieceColour) then
                                                  if (moveX == pieceX) then
                                                    if (moveY > pieceY) then
                                                      let newScore = score + (countOtherColour 0 moveY pieceY (pieces gameState) moveColour 0)
                                                      --recurse
                                                      if (tail(pieces) == []) then
                                                        return newScore
                                                      else
                                                        return eval move tail(pieces) moveColour gameState newScore
                                                    else
                                                      let newScore = score + (countOtherColour 0 pieceY moveY (pieces gameState) moveColour 0)
                                                      --recurse
                                                      if (tail(pieces) == []) then
                                                        return newScore
                                                      else
                                                        return eval move tail(pieces) moveColour gameState newScore
                                                  else
                                                    if (moveY == pieceY) then
                                                      if (moveX > pieceX) then
                                                        let newScore = score + (countOtherColour 1 moveX pieceX (pieces gameState) moveColour 0)
                                                        --recurse
                                                        if (tail(pieces) == []) then
                                                          return newScore
                                                        else
                                                          return eval move tail(pieces) moveColour gameState newScore
                                                      else
                                                        let newScore = score + (countOtherColour 1 pieceX moveX (pieces gameState) moveColour 0)
                                                        --recurse
                                                        if (tail(pieces) == []) then
                                                          return newScore
                                                        else
                                                          return eval move tail(pieces) moveColour gameState newScore
                                                    else
                                                      --recurse
                                                      if (tail(pieces) == []) then
                                                        return score
                                                      else
                                                        return eval move tail(pieces) moveColour gameState score
                                                else
                                                  --recurse
                                                  if (tail(pieces) == []) then
                                                    return score
                                                  else
                                                    return eval move tail(pieces) moveColour gameState score

countOtherColour :: Int -> Int -> Int -> [(Position, Col)] -> Col -> Int -> Int
countOtherColour xyFlag upper lower pieces turnColour score = do
                                                                --if xyFlag == 0 it's y aligned if 1 it's x aligned
                                                                let piece = head(pieces)
                                                                let pieceColour = other (snd piece)
                                                                let x = fst fst piece
                                                                let y = snd fst piece
                                                                if (pieceColour == turnColour) then
                                                                  if (xyFlag == 0) then
                                                                    if (upper > x && x > lower) then
                                                                      let newScore = score+1
                                                                      --recurse
                                                                      if (tail(pieces) == []) then
                                                                        return newScore
                                                                      else
                                                                        return countOtherColour xyFlag upper lower tail(pieces) turnColour newScore
                                                                    else
                                                                      --recurse
                                                                      if (tail(pieces) == []) then
                                                                        return score
                                                                      else
                                                                        return countOtherColour xyFlag upper lower tail(pieces) turnColour score
                                                                  else
                                                                    if (upper > y && y > lower) then
                                                                      let newScore = score+1
                                                                      --recurse
                                                                      if (tail(pieces) == []) then
                                                                        return newScore
                                                                      else
                                                                        return countOtherColour xyFlag upper lower tail(pieces) turnColour newScore
                                                                    else
                                                                      --recurse
                                                                      if (tail(pieces) == []) then
                                                                        return score
                                                                      else
                                                                        return countOtherColour xyFlag upper lower tail(pieces) turnColour score
                                                                else
                                                                  --recurse
                                                                  if (tail(pieces) == []) then
                                                                    return score
                                                                  else
                                                                    return countOtherColour xyFlag upper lower tail(pieces) turnColour score
Run Code Online (Sandbox Code Playgroud)

但是,此代码无法编译。我在第一行收到“if”上的“解析错误”,内容如下:

if (tail(pieces) == []) then
Run Code Online (Sandbox Code Playgroud)

这让我相信,我构建这段代码的方式的一些基本原理是错误的。我想澄清一下,我不是在找人来解决我的实现,只是找人向我解释我的实现是如何有缺陷的,以及如何以正确的方式实现递归来构建我的代码的一般指南.

如果您已经阅读了这么多,谢谢,我期待着阅读您的回复。

Fyo*_*kin 5

let在 a 之外时do,它需要一个in,例如:

-- correct
x =
    let a = 5
    in a + 37

-- incorrect
x =
    let a = 5
    a + 37
Run Code Online (Sandbox Code Playgroud)

所以当你if在 a 之后出现时letin它前面应该有一个right :

let newScore = score+1 
-- recurse
in if (tail(pieces) == []) then
       ...
Run Code Online (Sandbox Code Playgroud)

除此之外,您的代码中还有很多其他可以更简洁的内容。我不会介绍所有这些,只会举几个例子。

一个例子是let连续的多个绑定不需要let每个绑定:

x =
    let a = 5
        b = 37
    in a + b
Run Code Online (Sandbox Code Playgroud)

同样,条件if不需要括号,函数调用也不需要:

if tail pieces == [] then
Run Code Online (Sandbox Code Playgroud)

当我们在做的时候:通过null函数测试空列表而不是比较== []

if null (tail pieces) then
Run Code Online (Sandbox Code Playgroud)