Как понять Function as Functor
и Function as Applicative
?
Во-первых, как понимать функцию как функтор?
Мы можем рассматривать функтор как пустое поле, например:
instance Functor Maybe where
fmap :: (a -> b) -> f a -> f b
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
там Maybe
тип можно увидеть как пустое поле с одним слотом, которое принимает тип для создания конкретного типа Maybe a
. В функции fmap
:
- Первый параметр - это функция, которая отображает от a до b;
- Второй параметр - это значение типа с заполненным слотом (конкретный тип), этот конкретный тип создается конструктором типа и имеет тип fa (f равно
Maybe
, поэтому fa равно Maybe a
).
Когда мы реализуем функциональные функторы, для функциональных функторов должны быть два параметра, чтобы создать тип a -> b
, если мы хотим, чтобы наш функциональный функтор имел ровно один слот, мы должны сначала заполнить слот, поэтому конструктор типа функционального функтора будет ((->) р):
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
Так же, как функция fmap
в Maybe
Functor, мы должны рассматривать второй параметр g как значение конкретного типа, который генерируется с помощью f (f < / em> равно (->) r
), поэтому fa равно (->) r a
, что можно увидеть как r -> a
. Наконец, нетрудно понять, что g x в функции fmap
нельзя рассматривать как r -> x
, это просто приложение-функция, которое можно рассматривать как (r -> a) x
, также (x -> a)
.
Наконец, нетрудно понять, что функция ‹*> в Аппликативной функции (->) r
может быть реализована следующим образом:
<*> :: f (a -> b) -> f a -> f b
<*> :: (r -> a -> b) -> (r -> a) -> (r -> b)
<&> :: (a -> b) -> (r -> a) -> (r -> b)
f <*> g = \r -> f r (g r)
для gr отобразит r на a, fra отобразит r, a на b, поэтому всю лямбда-функцию можно увидеть как r -> b
, также как f b
. Например:
((+) <*> (+3)) 5
результат 5 + (5 + 3) = 13.
Как понять в функциях как аппликативы, (+) <$> (+3) <*> (*100) $ 5
= 508?
Мы знаем, что (+)
имеет тип: Num a, a -> a -> a
;
Мы также знаем, что (+3)
и (*100)
имеют тип: Num r, a, r -> a
;
(+) <$> (+3)
равно pure (+) <*> (+3)
, где :t pure (+)
равно Num _, a, _ -> a -> a -> a
Другими словами, pure (+)
просто принимает параметр _
и возвращает оператор +
, параметр _
не влияет на окончательное возвращаемое значение. pure (+)
также отображает возвращаемое значение функции (+3)
на функцию. Теперь для
f <*> g = \r -> f r (g r)
мы можем применить операторы и получить:
pure (+) <*> (+3) =
\r -> f r (gr) =
\r -> + (gr) =
\r -> + (r + 3) =
\r x -> x + (r + 3)
он имеет тип r -> x -> a
. Затем мы вычисляем pure (+) <*> (+3) <*> (*100)
, используя определение ‹*>, и получаем:
pure (+) <*> (+3) <*> (*100) =
\r -> f r (gr) =
\r -> (r + 3) + (gr)
\r -> (r + 3) + (r * 100)
затем применяем эту функцию с параметром 5, получаем:
(5 + 3) + (5 * 100) = 508
мы можем просто думать об этом аппликативном стиле как о первом вычислении значения после <$>
и суммировании их с помощью оператора до <$>
. В последнем примере этот оператор является двоичным оператором, равным (+)
, мы можем заменить его тройным оператором (\x y z -> [x,y,z])
, так что выполняется следующее уравнение:
(\x y z -> [x,y,z]) <$> (+3) <*> (*2) <*> (/2) $ 5 = [8.0,10.0,2.5]
person
Tri
schedule
27.02.2020
pure (+5)
отбрасывает свой первый аргумент, поэтому этоconst (+5) 4 $ (4 * 3)
или4 * 3 + 5
, что согласуется с(+5) . (*3) $ 4
. Кроме того,f <*> g = \x -> f (g x)
относится к типу(b -> c) -> (a -> b) -> (a -> c)
, который не проверяется ни с помощьюpure (+ 5) <*> (* 3) $ 4
, ни с объявлением классаApplicative
. - person schuelermine   schedule 24.06.2018