我正在尝试为具有函数属性的记录对象实现
functor
,如下所示:
data Function a =
Function {
, funcApply :: FData -> [Exp a] -> Either (RawException a) (Exp a)
}
因此,
funcApply
属性需要 fmap 到类型FData -> [Exp b] -> Either (RawException b) (Exp b)
。
映射返回值似乎很简单,并且让我得到类型
FData -> [Exp a] -> Either (RawException b) (Exp b)
:
instance Functor Function where
fmap f (Function funcApply) =
let funcApply' = \fData exps ->
case funcApply fData exps of
Left x -> Left $ fmap f x
Right x -> Right $ fmap f x
in Function funcApply'
但我真的不知道如何映射函数参数。从逻辑上讲,感觉
funcApply
根本不需要更改,因为它已经是多态的,但编译器似乎不同意。
感谢您的帮助!
应该根据所需的实例构建类型þ您找出什么映射对您的目的有用,并构建您的类型以反映它。正如已经指出的那样,在以混合极性出现的论证中不可能是函数式的:
{-# Language DeriveFunctor #-}
{-# Language DerivingStrategies #-}
{-# Language StandaloneKindSignatures #-}
import Data.Kind
-- • Can't make a derived instance of
-- ‘Functor Endo’ with the stock strategy:
-- Constructor ‘Endo’ must not use the type variable in a function argument
type Endo :: Type -> Type
newtype Endo a = Endo (a -> a)
deriving stock Functor
一个常见的技巧是按极性拆分论证:
-- (<–) (->) (->)
-- | | |
type Function :: Type -> Type -> Type
newtype Function іn out = Function (FData -> [Exp іn] -> Either (RawException out) (Exp out))
instance Profunctor Function where
-- Contravariant Covariant
-- vv vv
dimap :: (іn <– іn') -> (out -> out') -> (Function іn out -> Function іn' out')
dimap pre post (Function fn) = Function \fdata inExps ->
bimap (fmap post) (fmap post) (fn fdata (map (fmap pre) inExps))
然后您还可以获得有效的
Functor (Function іn)
instance Functor (Function іn) where
fmap :: (out -> out') -> (Function іn out -> Function іn out')
fmap = rmap
您的评论中的解决方案使其具有多态性也有效。这意味着没有要映射的参数,因此它不能有像 Functor 或 Profunctor 这样的更高种类的实例。
type Function :: Type
newtype Function = Function
(forall a. FData -> [Exp a] -> Either (RawException a) (Exp a))
由于它是多态的,因此您可以自由选择如何实例化它,但它也对什么可以被视为函数施加了严格的限制。现在它必须是参数化的
a。