簡體   English   中英

haskell中的一系列獨立if語句

[英]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或其他語言中完成的方式不同:

  • List(以及大多數其他數據結構)是不可變的。
  • 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM