[英]Alternative ways of defining zipWith using list comprehension without helper functions or extensions
[英]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
有以下三種情況:
第三種情況在參數的尾部遞歸調用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.