簡體   English   中英

使用列表推導重寫zipWith函數

[英]Rewriting zipWith function using list comprehension

我已經使用遞歸重寫了zipWith函數,現在我正嘗試使用列表理解來重寫它。 我遇到了很多綁定錯誤,並且我知道我的第二行是不正確的。 這是我使用遞歸使用zipWith的功能:

zipW :: (a -> b -> c) -> [a] -> [b] -> [c] 
zipW _ [] _ = []  
zipW _ _ [] = []  
zipW f (x:xs) (y:ys) = f x y : zipW f xs ys

這是我嘗試將其重寫為列表理解:

zipW2 :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW2 f xs ys = [f x y | (x, y) <- zipW2 f xs ys]

我不確定如何更正第二條語句,以便它像zipWith一樣工作,並允許我選擇運算符。

您將需要並行列表推導擴展:

{-# LANGUAGE ParallelListComp #-}

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = [f x y | x <- xs | y <- ys] 

原始zipWith有以下三種情況:

  1. 當第一個列表為空時
  2. 當第二個列表為空時
  3. 當兩個列表都不為空時

第三種情況在參數的尾部遞歸調用zipWith ,這再次進行了案例分析。

在您的定義中,只有一種情況-列表理解,因此任何遞歸調用都將回溯到這種情況。 如果沒有案例分析,您可以在這里永遠循環:

>>> let myZipWith f xs ys = [ f x y | (x,y) <- myZipWith f xs ys ]
>>> myZipWith (,) [] []
^CInterrupted.

此外,由於您在遞歸調用中使用f ,但要求遞歸輸出為對,因此您要隱式要求fxy產生一個對:

>>> :t myZipWith 
myZipWith :: (t2 -> t3 -> (t2, t3)) -> t -> t1 -> [(t2, t3)]

解決方案是不遞歸,而是直接考慮每對。

您可以使用behzad.nouri的啟用ParallelListComp語言擴展的解決方案

>>> :set -XParallelListComp
>>> let myZipWith f xs ys = [ f x y | x <- xs | y <- ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]

ParallelListComp使列表理解法律語法中的第二個(和更高版本)垂直豎線字符( | ),與較早的列表並行(類似zip)逐步瀏覽這些列表。

很高興知道這與普通列表理解有何不同,在常規列表理解中,您用逗號分隔了每個列表。 使用逗號進行嵌套迭代,該迭代在結果列表中被展平:

>>> let notZipWith f xs ys = [ f x y | x <- xs, y <- ys ]
>>> notZipWith (+) [1,2,4] [0,10,20]
[1,11,21,2,12,22,4,14,24]

使用ParallelListComp擴展實際上只是原始zipWith ,因此您可能會認為它是作弊行為。

您也可以只依賴原始的zip

>>> let myZipWith f xs ys = [ f x y | (x,y) <- zip xs ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]

但是由於zip被定義為zipWith (,) ,所以這也可能是作弊行為。

您可以使用的另一種方法是使用索引:

>>> let myZipWith f xs ys = [ f x y | i <- [0..min (length xs) (length ys) - 1], let x = xs !! i, let y = ys !! i ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]

但是,這將是非常低效的!! 是線性時間操作,使myZipWith二次方,而zipWith是線性的:

>>> :set +s
>>> last $ myZipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(4.80 secs, 3282337752 bytes)
>>> last $ zipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(0.40 secs, 2161935928 bytes)

我敢肯定還有其他不好的方法來創建等效於zipWith具有列表理解功能的方法,但是我並不十分相信有一個好的方法,即使是上面的方法也是如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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