[英]A series of independent if statements in haskell
可能是一個愚蠢的問題,但我不能為我的生活弄清楚這一點。
我想基於一系列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很新,所以請不要咬...
慣用,
x = concat [ [ "hi" ],
[ "hello" | True ],
[ "wait a minute..." | not True ],
[ "goodbye" | True ] ]
在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
簡單吧?
除了@ AaditMShah的答案之外,如果您只想附加一個值而不進行其他修改,那么編寫器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"
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"]
您需要了解在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 (hx))
,那么最左邊的函數f
應用於內向外持續。
如果你不喜歡這樣,你需要一個從左到右操作的($)替代品。 您可以編寫自己的函數(>>>),如下所示
res'= (
condAppend True "hello"
>>>
condAppend False "wait a minute"
>>>
condAppend True "goodbye"
) ["Hi"]
where
f >>> g = g . f
並且恰好在Control.Arrow中已經定義了(>>>>的一個很通用的版本)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.