繁体   English   中英

将C ++代码翻译成Haskell

[英]Translate C++ code to Haskell

我试图将这段c ++代码翻译成haskell但不能真正理解它。 这取自http://cs.stanford.edu/people/eroberts/courses/cs106b/chapters/07-backtracking-algorithms.pdf中的nim.cpp。

C ++:

const int MAX_MOVE = 3;
const int NO_GOOD_MOVE = -1;

int FindGoodMove(int nCoins) {
    for (int nTaken = 1; nTaken <= MAX_MOVE; nTaken++) {
        if (IsBadPosition(nCoins - nTaken)) return nTaken;
    }
    return NO_GOOD_MOVE;
}

bool IsBadPosition(int nCoins) {
    if (nCoins == 1) return true;
    return FindGoodMove(nCoins) == NO_GOOD_MOVE;
}

到目前为止,我在haskell做了:

findGoodMove nCoins = if isBadPosition (nCoins - nTaken) == True
                        then nTaken
                        else -1
                    where nTaken = 1

isBadPosition nCoins = if nCoins == 1
                        then True
                        else findGoodMove(nCoins) == -1

我陷入了for循环部分。 我真的想要一些关于如何将其翻译成haskell的建议。

提前致谢。

首先,我会使用Haskell的更丰富的类型系统来编码findGoodMove失败,给它类型

findGoodMove :: Int -> Maybe Int

并且isBadPosition可以具有该类型

isBadPosition :: Int -> Bool

接下来我们可以继续实施。 对于这一点,我将需要进口isNothingData.Maybe

import Data.Maybe

maxMove :: Int
maxMove = 3

findGoodMove :: Int -> Maybe Int
findGoodMove nCoins = loop 1
    where
        loop nTaken
            | nTaken == maxMove               = Nothing
            | isBadPosition (nCoins - nTaken) = Just nTaken
            | otherwise                       = loop (nTaken + 1)

isBadPosition :: Int -> Bool
isBadPosition 1      = True
isBadPosition nCoins = isNothing $ findGoodMove nCoins

因此,通过使用Maybe Int而不是Int for findGoodMove ,我们可以在类型系统级别编码,此函数具有单一故障模式(即NO_GOOD_MOVE ),我认为这会使意图更加清晰并确保我们不会意外地对待NO_GOOD_MOVE标志作为我们代码中其他地方的有效值。

对于循环部分,我已经定义了一个本地称为loop的递归函数,从1开始,并且有3个分支。 如果nTaken达到我们移动的最大值,我们已经到了循环结束并返回NothingNO_GOOD_MOVE )。 如果那个条件为False ,那么我们检查nCoins - nTaken是一个不好的位置,如果是,我们返回Just nTaken 如果这些条件都不是True ,那么我们再次使用nTaken + 1执行循环。

对于isBadPosition ,我们知道如果nCoins == 1 ,它是True ,所以我们可以使用模式匹配来处理这个简单的情况。 否则,我们必须知道findGoodMove nCoins成功,如果它不是Nothing ,它只会成功。 Data.Maybe.isNothing函数在这里很有用,可以快速检查它是否为NothingJust something ,因此它也使这个案例变得简单。

像这样的东西?

max_move = 3
no_good_move = -1

findGoodMove nCoins = findGoodMoveStep nCoins 1

findGoodMoveStep nCoins nTaken = if nTaken> max_move
                        then no_good_move
                        else if isBadPosition (nCoins - nTaken) == True
                        then nTaken
                        else findGoodMoveStep nCoins nTaken+1


isBadPosition nCoins = if nCoins == 1
                        then True
                        else findGoodMove(nCoins) == no_good_move

与@bheklilr的答案中定义loop函数不同,您可以使用列表理解 ,这是Haskell语言中的强大工具。 然后你可以使用模式匹配来正确选择nTaken

maxMove :: Int
maxMove = 3

findGoodMove :: Int -> Maybe Int
findGoodMove nCoins =
  let choices = [nTaken | nTaken <- [1..maxMove], isBadPosition (nCoins - nTaken)]
  in case choices of
    [] -> Nothing
    (nTaken:_) -> Just nTaken

isBadPosition :: Int -> Bool
isBadPosition 1 = True
isBadPosition nCoins = findGoodMove nCoins == Nothing

因为Haskell很懒。 列表choices将不会完全构建。 一旦找到第一个有效的nTaken它就会停止。 因此函数findGoodMove的时间复杂度与C ++版本相同。

暂无
暂无

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

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