在最少固定类型之后的haskell中的bifunctor

时间:2016-01-14 22:22:11

标签: haskell functor recursive-datastructures free-monad

我不确定如何在定点之后派生出函数实例:

data FreeF f a next  = PureF a | FreeF (f next)  deriving (Functor)

data Mu f  = In { out :: f ( Mu f ) }

newtype Free f a = Free(  Mu (FreeF f a)  )

instance Functor f => Functor (Free f) where
     fmap h (Free (out -> PureF a))  = Free (In (PureF (h a)))
     fmap h (Free (out -> FreeF fn)) = Free (In (fmap undefined undefined)) --stuck

如果我修改Mu以接受额外的类型参数,我可以继续进行直到......:

data Mu f a  = In { out :: f ( Mu f a )  } deriving (Functor)

newtype Free f a = Free(  Mu (FreeF f a) a )

instance Functor f => Functor (Free f ) where
     fmap h (Free (out -> PureF a))  = Free . In . PureF $ h a
     fmap h (Free (out -> FreeF fn)) = Free . In . FreeF $ fmap undefined fn 

在这里,我需要undefined :: Mu (FreeF f a) a -> Mu (FreeF f b) b,但mu f是同一f的仿函数,此处的类型不同。

解决这个问题的正确方法是什么?

2 个答案:

答案 0 :(得分:4)

  

mu f是同一个f的仿函数,此类型不同。

幸运的是,我们正在定义Functor (Free f),我们实际上使用此Functor实例来映射a构造函数中的PureFFunctor (Free f)摘录a的所有“内部”事件。

因此,每当我们想要映射两个a的出现时,例如当我们想要实现FreeF f a (Mu (FreeF f a)) -> FreeF f b (Mu (FreeF f b))时,我们可以通过将所有内容一直包装回Free来实现。 ,映射,然后再打开。

以下检查原始数据定义:

newtype Free f a = Free {unFree :: Mu (FreeF f a)} -- add "unFree"

instance Functor f => Functor (Free f) where
     fmap h (Free (In (PureF a)))  = Free (In (PureF (h a)))
     fmap h (Free (In (FreeF fn))) =
       Free (In (FreeF (fmap (unFree . fmap h . Free) fn)))

一些测试:

{-# LANGUAGE UndecidableInstances, StandaloneDeriving #-}

deriving instance Show (f (Mu f)) => Show (Mu f)
deriving instance Show (Mu (FreeF f a)) => Show (Free f a)       

foo :: Free [] Int
foo = Free $ In $ FreeF [ In $ PureF 100, In $ PureF 200 ]

> fmap (+100) foo
Free {unFree = In {out = FreeF [In {out = PureF 200},In {out = PureF 300}]}}

答案 1 :(得分:3)

我之前没有做过这种结构,但我想我已经看到了什么。你对Mu添加参数的直觉是好的,但你需要传递它以使Free f适合,即使f取两个参数而不是一个:

newtype Mu f a = In { out :: f (Mu f a) a }

Mu f在合适的条件下应该是Functor,它会为您提供您正在寻找的实例。这些条件是什么?我们需要:

fmap' :: (a -> b) -> f (Mu f a) a -> f (Mu f b) b

我们希望f在其第二个参数中是函数式的,所以这没问题。那么我们真正需要一种方法来获得

f (Mu f a) b -> f (Mu f b) b
           ^               ^
           +--not varying--+

我们可以递归地使用实例来获取Mu f a -> Mu f b,所以看起来我们只需要f在其第一个参数中成为一个仿函数。因此:

class Bifunctor f where
    bimap :: (a -> c) -> (b -> d) -> f a b -> f c d

然后你应该能够编写合适的实例

instance (Functor f) => Bifunctor (FreeF f) ...
instance (Bifunctor f) => Functor (Mu f) ...