Экземпляр функтора
У меня есть следующий тип newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a }
, И я должен написать экземпляр Functor для этого, но я не очень понимаю, как я пытался
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (g a)
а также
instance Functor (Arr2 e1 e2) where
fmap g = g . getArr2
что на самом деле приводит к типу
(a -> b) -> Arr2 e1 e2 a -> b
вместо желаемого
(a -> b) -> Arr2 e1 e2 a -> Arr2 e1 e2 b
Пожалуйста, помогите мне
2 ответа
Functor
класс имеет в качестве определения:
class Functor f where:
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
(<$)
имеет реализацию по умолчанию: (<$) = fmap . const
который отлично работает
Так что это означает, что если мы введем функцию (g :: a -> b
) в качестве первого аргумента и Arr2
который производит a
мы должны сгенерировать Arr2
что называет это g
на исходе стрелки, если он применяется.
В результате определение fmap
для тебя Arr2
является:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (\x y -> g (a x y))
Или более элегантно:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 (\x -> g . (a x))
Или более элегантная версия - комментирует @Alec:
instance Functor (Arr2 e1 e2) where
fmap g (Arr2 a) = Arr2 ((g .) . a)
(Вы можете конвертировать выражения в точечные, используя этот инструмент)
Ответ от Willem Van Onsem очень хороший, я просто хотел бы предложить использовать расширение языка, которое может легко создать Functor
экземпляры для новых типов: DeriveFunctor
,
В верхней части вашего модуля вы можете добавить:
{-# LANGUAGE DeriveFunctor #-}
Тогда вы можете автоматически получить ваш Functor
пример:
newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a } deriving Functor
Вот как бы я узнал тип fmap
для этого экземпляра в GHCi:
λ > :set -XDeriveFunctor
λ > newtype Arr2 e1 e2 a = Arr2 { getArr2 :: e1 -> e2 -> a } deriving Functor
λ > :set -XTypeApplications
λ > :t fmap @(Arr2 _ _)
fmap @(Arr2 _ _) :: (a -> b) -> Arr2 t t1 a -> Arr2 t t1 b