我寫了一個簡單的函數現在哈斯克爾 - 改寫參數會導致意外行爲
someFunc list elem = do
list <- elem:elem:elem:list
return elem
,當我使用它,我得到的輸出喜歡這個
*Main> someFunc [] 'a'
"aaa"
儘管事實上,這個功能沒有實際用途,爲什麼會發生?爲什麼編輯列表在elem
中有效?以及如何爲list
分配新值以避免這種情況?
我寫了一個簡單的函數現在哈斯克爾 - 改寫參數會導致意外行爲
someFunc list elem = do
list <- elem:elem:elem:list
return elem
,當我使用它,我得到的輸出喜歡這個
*Main> someFunc [] 'a'
"aaa"
儘管事實上,這個功能沒有實際用途,爲什麼會發生?爲什麼編輯列表在elem
中有效?以及如何爲list
分配新值以避免這種情況?
你是(顯然不小心)使用列表monad。在Python中,你的摘要將表示爲:
for list in [elem, elem, elem] + list:
yield elem
也就是說,您創建一個包含一個elem
列表中的每個項目,再加上三個列表。
這裏就是你可能打算:
someFunc list elem = do
list <- return (elem:elem:elem:list)
return elem
這只是創建了一個新變量list
陰影舊的一個,並且完全忽略它返回elem
。
您可以將新值不分配給list
,發生的事情是在<-
左側的list
是比list
在<-
權不同。如果您打開與-Wall
警告你會看到
<interactive>:13:19: Warning:
This binding for `elem' shadows the existing binding
imported from `Prelude' (and originally defined in `GHC.List')
<interactive>:14:7: Warning:
This binding for `list' shadows the existing binding
bound at <interactive>:13:14
<interactive>:14:7: Warning: Defined but not used: `list'
您沒有使用list <- ...
定義的名稱list
,只是定義它,這樣它發生影着現有綁定。
原因someFunc [] 'a'
返回"aaa"
是由於列表monad的工作原理。這做記號將相當於
someFunc list e = (e:e:e:list) >>= \l -> return e
而對於名單,>>=
基本上是concatMap
,所以你必須
someFunc list e = concatMap (\l -> return e) (e:e:e:list)
在[]
所以替代list
和'a'
爲e
我們得到
someFunc [] 'a' = concatMap (\l -> return 'a') "aaa"
= concat $ map (\l -> return 'a') "aaa"
= concat [['a'], ['a'], ['a']]
= ['a', 'a', 'a']
= "aaa"
您的困惑可能來自使用return
。在大多數語言中,return
是一個關鍵字,但在Haskell中它只是一個函數。它不提前退出函數調用,它所做的只是在您所在的monad環境中包裝一個值。對於列表return x = [x]
,這就是整個定義。另外,在Haskell中,你不能重新賦值,但你可以用新的定義來隱藏它們。不過,如果您總是使用-Wall
和-Werror
進行編譯,您將不會遇到此問題。
請注意,您的功能將被取消加糖到這一點:
someFunc :: [b] -> b -> [b]
someFunc list elem = (elem:elem:elem:list) >>= \list -> return elem
現在注意到,在\list -> return elem
的list
爲你傳遞給函數的輸入list
不同。
現在看到的名單單子實例定義:
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
所以,你的代碼轉換爲這種形式最後:
someFunc list elem = concat $ map (\list -> return elem) (elem:elem:elem:list)
現在你能理解爲什麼您獲得的輸出?
someFunc [] 'a'
將得到應用這樣的:
concat $ map (\list -> return 'a') ('a':'a':'a':[])
concat $ [['a'],['a'],['a']]
'a':'a':'a':[]
"aaa"
的脫糖去'someFunc列表ELEM =(ELEM:ELEM:ELEM:列表)>> =(\列表 - >回ELEM)'; desugaring沒有引入新的可用'x'。 –
@GPhilip謝謝,更新。我最初把它保存爲'x',以確保OP瞭解與輸入值不同的'list'。 – Sibi