[英]Haskell: How to return a list of possible splits of a list
我正在嘗試編寫一個名為split的函數,它接受一個列表並返回所有不同可能性的對列表以對其進行分區,例如
split [4,3,6] = [([],[4,3,6]),([4],[3,6]),([4,3],[6]),([4,3,6],[])]
現在我寫了這個
split :: [a] -> [([a],[a])]
split [] = [([],[])]
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst split(xs))) (map snd split(xs)))
一段代碼和Hugs以及我選擇的翻譯讓我知道了
ERROR file:.\split.hs:3 - Type error in application
*** Expression : map snd split xs
*** Term : map
*** Type : (e -> f) -> [e] -> [f]
*** Does not match : a -> b -> c -> d
錯誤信息。 我到底做錯了什么? 為什么(map snd split xs)屬於類型
(a-> b - > c - > d)?
你錯了你的parens。 嘗試
split (x:xs) = ([],(x:xs)):(zip (map (x:) (map fst (split xs))) (map snd (split xs)))
Haskell不像C和Java那樣使用括號進行函數調用。 當您編寫map fst split(xs)
這與map fst split xs
相同,即編譯器認為您嘗試使用三個參數調用map
。 因此,您需要將調用split
如下所示: map fst (split xs)
。
你有效地嘗試編寫的是一個列表的簡單拉鏈 。 實現它的最簡單方法是
import Data.List (inits, tails)
split xs = zip (inits xs) (tails xs)
這是另一種定義:
splits :: [a] -> [(a, a)]
splits xs = map (flip splitAt xs) [0 .. length xs]
不可否認,這不是很有效,但至少它簡潔:-)
另一個版本,甚至更短,而且可能更有效,使用inits
和tails
從Data.List
:
splits :: [a] -> [(a, a)]
splits xs = zip (inits xs) (tails xs)
現在讓我們玩得開心吧。 我們可以將inits
和tails
寫為foldr
,其中我們使用initsA
和tailsA
來表示所謂的折疊代數 :
inits :: [a] -> [[a]]
inits = foldr initsA [[]]
initsA :: a -> [[a]] -> [[a]]
initsA x xss = [] : map (x:) xss
tails :: [a] -> [[a]]
tails = foldr tailsA [[]]
tailsA :: a -> [[a]] -> [[a]]
tailsA x xss = (x : head xss) : xss
使用這些代數,我們可以進一步組合它們:
splits :: [a] -> [([a], [a])]
splits = foldr splitsA [([], [])]
splitsA :: a -> [([a], [a])] -> [([a], [a])]
splitsA xy xyss = zip (initsA xy xss) (tailsA xy yss)
where (xss, yss) = unzip xyss
所以現在我們splits
定義為單個foldr
!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.