![](/img/trans.png)
[英]Python how to apply map function on elements of list if possible?
[英]Does indexing a mapped/filtered infinite list apply the map/filter function to all the elements before the index?
If I define an infinite list and call map over it with a function, I can take some number of elements from the beginning and Haskell will generate and apply the function only to these elements due to lazy evaluation
-- This will generate and process 10 elements
doubledNumbers = map (*2) [0..]
take 10 doubledNumbers
如果我改為索引這個無限映射
doubledNumbers !! 9
將 Haskell 生成該點之前的列表,將映射 function 應用於所有元素並將索引 9 處的元素返回; 或者它會生成列表,將映射 function 應用到索引 9 處的元素,然后返回。 換句話說,當我調用doubledNumbers !! 9
doubledNumbers !! 9
第二種解釋是正確的(嗯,至少在道德上:見下文以獲得更好的解釋):
- 生成列表
[0,1,2,3,4,5,6,7,8,9]
,然后從該列表中取出 9 並提供給(*2)
,然后(*2)
返回 18
通過以下實驗,您可以觀察到 function(在您的情況下為(*2)
)不適用於其他元素。 首先,定義一個 function,它將在除 9 之外的每個數字上崩潰:
f 9 = 100 ; f _ = error "urk!"
然后在 GHCi 中嘗試你的代碼,適應新的 function
> doubledNumbers = map f [0..]
> doubledNumbers !! 9
100
如果 GHCi 將f
應用於任何其他數字,您將觀察到崩潰。 這是一種通過實驗區分惰性評估和急切評估的方法。
更迂腐的是,在 GHCi 中輸入代碼
> doubledNumbers = map (*2) [0..]
> doubledNumbers !! 9
將首先生成一個類似於
(*2) 0 : (*2) 1 : .... : (*2) 9 : map (*2) [10..]
其中表達式尚未計算。 之后,GHCi 將提取第 9 個,對其進行評估和打印。
兩種解釋都不正確。 實際上,可以認為生成的列表看起來像這樣:
[_,_,_,_,_,_,_,_,_,_...
換句話說,列表的脊椎或形狀被強制向上通過第 9 個元素(僅此而已),但列表中的實際值不是。 然后,當您請求映射列表的第 9 個元素時,除非必要,否則 GHC 在該元素上調用 function 而不對其進行評估。 您可以通過以下實驗觀察到這一點:
errorList = repeat (error "fail!")
trueList = map (const True) errorList
val = trueList !! 9
如果列表實際上是首先生成的,那么val
會因失敗而fail!
一旦我們嘗試打印它。 但是, val
正確地是True
。
通常可以使用 Haskell 運行時庫中包含的一個小而方便的跟蹤工具來回答此類問題。
所以有一個trace
function,這樣計算表達式trace debugMsg expr
將返回expr
的值,並且作為副作用,將debugMsg
的值打印到標准錯誤通道。
是的,副作用在 Haskell 中通常不可用,但trace
function 享有特殊特權:-)
因此,您可以將(*2)
function 替換為等效的:
import qualified Debug.Trace as DT
doubler :: Int -> Int
doubler x = let debugMsg = "Doubling " ++ (show x) ++ " ... "
in DT.trace debugMsg (2*x)
然后你可以在ghci
解釋器下測試各種假設:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> :load q65861408.hs
[1 of 1] Compiling Main ( q65861408.hs, interpreted )
Ok, one module loaded.
λ>
λ> :type doubler
doubler :: Int -> Int
λ>
λ> doubler 5
Doubling 5 ...
10
λ>
λ> doubledNumbers = map doubler [0..]
λ>
λ> doubledNumbers !! 9
Doubling 9 ...
18
λ>
因此,正如其他答案中所提到的,加倍 function 似乎僅針對輸入值 9 調用。
這是因為語言懶惰:用戶沒有要求查看其他加倍的值,因此不需要首先計算它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.