可能是一个愚蠢的问题,但我无法解决这个问题。
我想基于一系列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很新,所以请不要咬......
答案 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中已经定义了(>>>)(>>>)。