【问题标题】:list understanding and recursive if statements in Haskell列出 Haskell 中的理解和递归 if 语句
【发布时间】:2021-06-26 10:58:25
【问题描述】:

我目前正在以多种方式练习 Haskell。 使用列表创建大量有趣的东西。 现在我(认为)在理解 if 语句方面遇到了问题。

我想做的是制作一个焦点列表,将焦点转移到最左边的项目。 焦点列表已经相当棘手,本质上是两个独立的列表。 它还将整个列表分成两半,并反转后列表。

例如。如果你想创建一个 [0,1,2,3,4,5] 的焦点列表,并希望将焦点放在 3 上,那么焦点列表将是 [3,4,5][2,1,0]。

我已经做了三个具体的功能。 一种使焦点列表数据类型:

data FocusList a = FocusList { forward :: [a], backward :: [a]}

你可以使用它来调用它

fromList :: [a] -> FocusList a
fromList list = FocusList list []

将其从焦点列表更改回列表:

toList :: FocusList a -> [a] 
toList (FocusList fw bw) = reverse bw ++ fw

将其向左移动一次,将 [0,1,2,3,4,5] 更改为 [0,1,2,3, 4,5] 现在看起来像 [2,3,4,5][0,1] 作为焦点列表:

goLeft :: FocusList a -> FocusList a
goLeft (FocusList fw (f:bw)) = FocusList (f:fw) bw

现在,进入重点。如果我将它一直向左移动。我想使用 goLeft 直到列表的长度为 1。我正在考虑使用递归 if 语句,直到第一个列表的长度等于 1。如果不是一个,则使用 goLeft。

所以我想到了一个简单的 if 语句。哪个(现在)根本不起作用。 它使用leftMost :: FocusList a -> FocusList a

leftMost (FocusList fw (f:bw)) =  if (length (FocusList fw) == 1)
                                    then FocusList (f:fw) bw
                                    return leftMost
                                   else FocusList fw (f:bw)

我正在以 Python 的方式思考它。这似乎不起作用。如何使其逻辑递归?

【问题讨论】:

  • "right" 和 "left" 会是更有用的名称。将右侧组件放在左侧也令人困惑。此外,Haskell 是 expression-oriented language

标签: if-statement haskell recursion focus


【解决方案1】:

不要使用length,它需要花费 O(N),因为它必须扫描整个列表。如果您改为使用模式匹配,在这种情况下您只需支付 O(1) 成本。

一个简单的方法是使用两个方程,一个接一个地尝试。

leftMost :: FocusList a -> FocusList a
-- if there's only one backward item, leave the list as it is
leftMost (FocusList fw [f]) = FocusList fw [f]
-- otherwise, goLeft, then recurse
leftMost fl                 = leftMost (goLeft fl)

模式[f] 仅匹配具有单个项目的列表。相当于(f:[])

请注意,如果后向部分为空,上面的代码将崩溃。如果这是一个问题,您需要通过添加更多方程来解决这个问题。

或者,可以使用 as-pattern 来缩短代码:

leftMost :: FocusList a -> FocusList a
leftMost fl@(FocusList fw [f]) = fl    -- fl is the whole input
leftMost fl                    = leftMost (goLeft fl)

如果我们愿意,我们也可以内联goLeft

leftMost :: FocusList a -> FocusList a
leftMost fl@(FocusList fw [f]) = fl
leftMost (FocusList fw (f:bw)) = leftMost (FocusList (f:fw) bw)

甚至可以处理上面提到的empty-backward-list问题:

leftMost :: FocusList a -> FocusList a
leftMost fl@(FocusList fw     [f])    = fl
leftMost    (FocusList fw     (f:bw)) = leftMost (FocusList (f:fw) bw)
leftMost    (FocusList (f:fw) [])     = FocusList fw [f]
leftMost    (FocusList []     [])     = error "leftMost: empty list"

最后一种情况,指的是一个空列表,很难以合理的方式处理。您可以选择崩溃并显示错误消息(如上所述),返回空列表(这是预期的结果吗?),或者通过返回 Maybe (FocusList a) 来向调用者报告错误。

【讨论】:

    猜你喜欢
    • 2015-03-10
    • 2013-03-06
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2019-12-04
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多