haskell中的一系列独立if语句

时间:2014-09-20 08:11:13

标签: haskell if-statement

可能是一个愚蠢的问题,但我无法解决这个问题。

我想基于一系列if语句附加到列表的末尾。

在python(或我熟悉的大多数其他语言)中,我可以这样做:

x = ["hi"]
if True:
    x.append("hello")
if not True:
    x.append("wait a minute...")
if True:
    x.append("goodbye")

哪会给我:

['hi', 'hello', 'goodbye']

如何在Haskell中实现这样的目标?

我可以达到:

res :: [[Char]]
res =
    let x = ["Hi"]
    in
        if (True)
            then x ++ ["hello"]
            ... what goes here???
        else x

或者我是否完全错了?

我对Haskell很新,所以请不要咬......

5 个答案:

答案 0 :(得分:10)

惯用,

x = concat [ [ "hi" ],
             [ "hello" | True ],
             [ "wait a minute..." | not True ],
             [ "goodbye" | True ] ]

答案 1 :(得分:6)

在Haskell中,每个if表达式必须具有else子句。在这方面,它类似于Python条件运算符:

a if test else b

在Haskell中,它将写成:

if test then a else b

那么你如何在Haskell中编写以下内容?

x = ["hi"]
if True:
    x.append("hello")

您可以这样做:

let x = ["hi"] in
if True then x ++ ["hello"] else x

请参阅else条款?它只是按原样返回值。


然而,写这样的代码很糟糕。我们想要像Python一样编写代码,而Python则是有状态的。变量x是状态。在Haskell中,我们有State monad来编写这样的代码。考虑:

import Control.Monad.State

append a = modify (++ [a])

foo :: [String] -> [String]
foo = execState $ do
    when True       $ append "hello"
    when (not True) $ append "wait a minute..."
    when True       $ append "goodbye"

x = ["hi"]

res = foo x

main = print res

简单吧?

答案 2 :(得分:6)

除了@ AaditMShah的答案之外,如果您只想附加一个值而不进行其他修改,writer monad将是正确的抽象:

import Control.Monad
import Control.Monad.Writer

append :: a -> Writer [a] ()
append = tell . (: [])

x :: [String]
x = execWriter $ do
        tell ["hi"]
        when True $
            append "hello"
        when (not True) $
            append "wait a minute..."
        when True $
            append "goodbye"

答案 3 :(得分:5)

Haskell与在Python或其他语言中完成的方式不同:

  • 列表(以及大多数其他数据结构)是不可变的。
  • if else是Haskell中的表达式,而不是其他语言中的语句。您不能忽视Haskell中的else部分,就像您使用Python所做的那样。

查看你的python代码,你想要做的似乎是如果条件是True,那么你想要一个元素附加到列表中。该模式可以在以下函数中抽象出来:

appendIfTrue :: Bool -> a -> [a] -> [a]
appendIfTrue b x xs = if b
                      then xs ++ [x]
                      else xs

编写完该功能后,您可以使用以下代码实现相同的功能:

x = ["hi"]

main = do
  let x1 = appendIfTrue True "hello" x
      x2 = appendIfTrue False "wait a minute" x1
      x3 = appendIfTrue True "goodbye" x2
  print x3

这里要注意的是,您在这里创建一个新列表,而不是像在Python代码中那样修改它们。 演示:

λ> main
["hi","hello","goodbye"]

答案 4 :(得分:3)

您需要了解在Haskell中,您不能像在python示例中那样修改x。您需要通过条件线程化一个值(一个字符串列表),其中每个步骤附加或不附加另一个字符串。因此,您无法单独使用嵌套的if-then-else语句。您需要访问到目前为止构建的中间字符串列表。

因此,基本操作是基于布尔值附加或不将字符串附加到字符串列表。执行这种条件的函数可以看起来像:

condAppend :: Bool -> String -> [String] -> [String]
condAppend c suff pref = if c then pref ++ [suff]
                         else pref

不,你只需链接一系列condAppends并将其应用于inial字符串列表:

res = condAppend True "goodby" 
      $ condAppend False "wait a minute" 
      $ condAppend True "hello" ["Hi"]

这会给你:

["Hi","hello","goodby"]

请注意,res中的执行顺序是从下到上(如果你在一行中全部写入,则是从右到左),或者如果你喜欢,则在f (g (h x))中最左边的函数{{ 1}}最后应用。

如果你不喜欢这样,你需要一个从左到右操作的($)替代品。您可以在

中编写自己的函数(>>>)
f

并且恰好在Control.Arrow中已经定义了(>>>)(>>>)。