直觀上,unzip'
函數具有推倒保持(a,b)
的結構,然後構建它到該結構的兩個副本,其中第一個包含a
並且其包含b
第二。
一個可能的推廣,在另一個答案已經提到的,是
unzip' :: (Functor t) => t (a, b) -> (t a, t b)
unzip' xs = (fmap fst xs, fmap snd xs)
這符合該法案,但一個缺點是,它的初始結構越過兩次 - 一次每次調用fmap
。
的Foldable
類描述可以遍歷,構建一個結果,因爲我們去的結構。我們可以利用這個屬性來確保我們只傳遞一次初始結構(一次調用foldr
),但我們仍然需要知道如何再次構建結構的副本。
的MonadPlus
型類提供的方法來得到一個空的結構,並結合了兩種結構(有點像高階Monoid
) -
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
有了這個,我們可以寫
import Control.Monad
import Data.Foldable (foldr)
unzip' :: (Foldable t, MonadPlus m) => t (a, b) -> (m a, m b)
unzip' = foldr f (mzero, mzero)
where
f (a,b) (as, bs) = (mplus (return a) as, mplus (return b) bs)
然後我們可以做像
>> unzip' [(1,2), (3,4)] :: ([Int], [Int])
([1,3],[2,4])
而且
>> unzip' (Right (1,2)) :: ([Int], Maybe Int)
([1],Just 2)
最終的一個想法 - 這是一個有點醜,我們需要調用mplus (return a) as
。這可能是更好的類似
class Listish m where
null :: m a
cons :: a -> m a -> m a
但我沒有真正探索這一點的設計空間。
[Data.Align.Unalign](http://hackage.haskell.org/package/these-0.6.2.1/docs/Data-Align.html#t:Unalign) –
相關:背後的「更深意義」 _zip_正在[right adjoint](https://hackage.haskell.org/package/adjunctions-4.3/docs/Data-Functor-Adjunction.html)。 – Turion