方阵函数

Functor for square matrices

在我之前的问题 () 中,引入了数据类型 Square。现在我想为它写一个仿函数实例。所以我从所有四种类型的地图函数开始。我已经为 NilCons:

做到了
mapNil :: ((a -> b) -> a -> b) -> (Nil (a -> b) -> Nil a -> Nil b )
mapNil map f Nil = Nil


mapCons :: (forall b . ((a -> b) -> a -> b) -> (t (a -> b) -> t a -> t b))
        -> ((a -> b) -> a -> b)
        -> ((Cons t (a -> b)) -> Cons t a -> Cons t b)
mapCons mapT mapA (Cons f consf) (Cons x consx) =  Cons (mapA f x) (mapT mapA consf consx)

现在,Square' 类型:

mapSquare' :: (forall b . ((a -> b) -> a -> b) -> (t (a -> b) -> t a -> t b))
           -> ((a -> b) -> a -> b)
           -> ((Square' t (a -> b)) -> Square' t a -> Square' t b)
mapSquare' mapT mapA (Zero fs) (Zero xs) = Zero (mapT (mapT mapA) fs xs) -- it is wrong
mapSquare' mapT mapA (Succ fs) (Succ xs) = mapSquare' (mapCons mapT) mapA fs xs

然后我会做这样的事情:

mapSquare = ...

-- this is, actually, the final goal:
instance Functor Square where
fmap = mapSquare

到目前为止,我的 mapSquare' Haskell 是这样说的:

• Occurs check: cannot construct the infinite type: a ~ t a
  Expected type: (a -> t b) -> a -> t b
    Actual type: t (a -> b) -> t a -> t b
• In the first argument of ‘mapT’, namely ‘(mapT mapA)’
  In the first argument of ‘Zero’, namely ‘(mapT (mapT mapA) fs xs)’
  In the expression: Zero (mapT (mapT mapA) fs xs)

我的计划是 (mapT mapA) 将 "lift" 全部介于 (t (t a))(t a) 之间。我的错误是什么?我将不胜感激你的帮助。

您不能使用 mapSquare,因为该类型限制太多。函子的类型为 fmap :: Functor f => (c -> d) -> f c -> f d。但是 ((a -> b) -> a -> b) -> (Square (a -> b)) -> Square a -> Square b 只会涵盖其中的一个子集。您的 mapSquare' 看起来更像是“ 顺序应用程序 (<*>) :: Applicative f => f (a -> b) -> f a -> f b。请注意 (<*>) 需要两个 f <i>x</i> 项,而不是一个,就像 fmap 那样。

如果你想声明 Square Functor 的一个实例,根据你的实现方式,NilConst 可能需要也是 Functor 的一个实例。我们可以很容易地使这些成为 Functor:

的实例
instance Functor Nil where
    fmap _ Nil = Nil

instance Functor t => Functor (Cons t) where
    fmap f (Cons x xs) = Cons (f x) (fmap f xs)

现在我们可以使 Square' 成为 Functor 的一个实例:

instance Functor t => Functor (Square' t) where
    fmap f (Zero x) = Zero (fmap (fmap f) x)
    fmap f (Succ x) = Succ (fmap f x)

你实际上并没有自己生成那些。您可以使用 DeriveFunctor [ghc-doc] 编译器选项,让编译器为您派生函数:

{-# LANGUAGE <b>DeriveFunctor</b> #-}

data Square' t a = Zero (t (t a) ) | Succ (Square' (Cons t) a) <b>deriving Functor</b>
data Nil a = Nil <b>deriving Functor</b>
data Cons t a = Cons a (t a) <b>deriving Functor</b>

这将构造此处讨论的指定函子。

这里是我想问的问题的答案,而不是实际问的,因为我的表达方式有点含糊。 首先,我确实搞砸了 (<*>)fmap,感谢@WillemVanOnsem 指出了这一点。 所以,我真正想做的是:

mapNil :: ((a -> b) -> a -> b) -> ((a -> b) -> Nil a -> Nil b )
mapNil mapA f Nil = Nil

mapCons :: (forall b . ((a -> b) -> a -> b) -> ((a -> b) -> t a -> t b))
        -> ((a -> b) -> a -> b)
        -> ((a -> b) -> Cons t a -> Cons t b)
mapCons mapT mapA f (Cons x consx) =  Cons (f x) (mapT mapA f consx)

然后...

mapSquare' :: (forall b . ((a -> b) -> a -> b) -> ((a -> b) -> t a -> t b))
           -> ((a -> b) -> a -> b)
           -> ((a -> b) -> Square' t a -> Square' t b)
mapSquare' mapT mapA f (Zero xs) = Zero (mapT (mapT mapA) f xs) 
mapSquare' mapT mapA f (Succ xs) = Succ (mapSquare' (mapCons mapT) mapA f xs)

t 是类型 * -> * 的类型构造函数,因此 t (mapT) 上的映射函数应该在其参数 (mapA) 作为参数。所以我需要 mapTmapA