解压缩的概括是什么?

时间:2016-03-01 10:25:12

标签: list haskell typeclass

我从列表中了解到的大多数方法实际上是一些众所周知的类型类的特例。方法和相关类型类的一些示例:

  • map :: (a -> b) -> [a] -> [b]Functor
  • foldr :: (a -> b -> b) -> b -> [a] -> bFoldable
  • forM :: Monad m => [a] -> (a -> m b) -> m [b]Traversable
  • concat :: [[a]] -> [a]Monad

可能列表继续(原谅双关语)。

我想知道更深刻的含义"在unzip :: [(a, b)] -> ([a], [b])之后。是否可以使用[]的一些着名实例来实现,例如(,a)的仿函数实例?或者其他一些情况?理想情况下,我希望使用此类型的更抽象的函数:SomeClass m => unzip :: m (a, b) -> (m a, m b)。是否有一个课程可以使这项工作?

2 个答案:

答案 0 :(得分:7)

您可以简单地进行第一次和第二次预测:

gunzip :: Functor f => f (a, b) -> (f a, f b)
gunzip ps = (fmap fst ps, fmap snd ps)

但请注意gunzip遍历ps两次不同于通常的zip列表,所以它很麻烦,因为ps在第一次之后不会被垃圾回收传递并停留在内存中,这会导致大列表中的内存泄漏。

答案 1 :(得分:6)

直观地说,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

但我还没有真正探索过这个设计空间。