在我上一个问题(Nested datatype for square matrices)中,引入了数据类型Square
。现在,我想为其编写一个仿函数实例。因此,我首先从所有四种类型的地图函数开始。我已经为Nil
和Cons
做到了这一点:
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)
将在(t (t a))
和(t a)
级别之间“提升”它们。我怎么了多谢您的协助。
答案 0 :(得分:4)
您不能使用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 x
项,而不是fmap
那样的项。
如果您要声明Square
的一个实例,则Functor
和Nil
可能是一个Const
和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)
的实例,
{-# LANGUAGE DeriveFunctor #-}
data Square' t a = Zero (t (t a) ) | Succ (Square' (Cons t) a) deriving Functor
data Nil a = Nil deriving Functor
data Cons t a = Cons a (t a) deriving Functor
您实际上并不自己生成那些。您可以使用DeriveFunctor
[ghc-doc]编译器选项,并让编译器为您派生功能:
#config
---
lists:
- filename: filename.xlsx
template: filename_template.xlsx
type: classType #this value is ommitted
...
这将构造此处讨论的指定函子。
答案 1 :(得分:1)
这是我要提出的问题的答案,而不是实际提出的问题,因为我的说法有点含糊。
首先,我确实搞砸了,将(<*>)
与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
)上的映射函数应在其参数({{1} })作为参数。所以我需要mapA
和mapT