Подтвердить что ты не робот

Путают о функции как пример Functor в haskell

тип fmap в Functor:

fmap :: Functor f => (a -> b) -> f a -> f b

похоже, сначала примените функцию (a → b) к параметру f a, чтобы создать результат типа b, затем примените f к нему, а результат будет f b

using Может быть, например:

 fmap show (Just 1)
 result is : Just "1"

то же самое, что сказать:

Just (show 1)

но когда (- > ) используется как функтор (в Control.Monad.Instances)

import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"

то есть Just применяется сначала, а затем применяется show. в другом примере результат будет таким же:

 fmap (*3) (+100) 1
 result is 303

почему не * 3 сначала, а затем +100?

4b9b3361

Ответ 1

тип fmap в Functor:

fmap :: Functor f => (a -> b) -> f a -> f b

это выглядит, сначала примените функцию (a → b) к параметру f a для создания результата типа b, затем примените f к нему, и результатом будет f b

Это тип fmap, но ваша интерпретация того, что означает этот тип, неверна.

Предполагается, что f a имеет один параметр и этот параметр имеет тип a.

Рассмотрим xs :: [a]:

  • Возможно xs = [].
  • Возможно xs = [x1].
  • Возможно xs = [x1, x2].
  • ...

Тип f a является функтором f с параметром одного типа a. Но значения типа f a необязательно принимают вид F x, как вы можете видеть из первого и третьего случаев выше.

Теперь рассмотрим fmap f xs:

  • Возможно fmap f xs = [].
  • Возможно fmap f xs = [f x1].
  • Возможно fmap f xs = [f x1, f x2].
  • ...

Мы не обязательно применяем f вообще (первый случай)! Или мы можем применить его более одного раза (третий случай).

Что мы делаем, это заменить вещи типа a, с вещами типа b. Но мы оставляем большую структуру неповрежденной --- никаких новых элементов не добавлено, никаких элементов не удалено, их порядок остается неизменным.


Теперь подумайте о функторе (c ->). (Помните, что функтор принимает только один параметр типа, поэтому вход в (->) фиксирован.)

Есть ли c -> a даже a? Он вообще не может содержать никаких a, но он может каким-то волшебным образом излучением из воздуха, когда мы дадим ему c. Но результат из fmap имеет тип c -> b: нам нужно предоставить только b, если нам будет представлен c.

Итак, мы можем сказать fmap f x = \y -> f (x y).

В этом случае мы применяем f по запросу --- каждый раз, когда применяется возвращаемая функция, применяется также f.

Ответ 2

Экземпляр fmap для (->) r (т.е. функции) - это буквально только композиция. Из самого источника:

instance Functor ((->) r) where
    fmap = (.)

Итак, в вашем примере мы можем просто заменить fmap на (.) и сделать некоторые преобразования

fmap (*3) (+100) 1 => 
(.) (*3) (+100) 1  =>
(*3) . (+100) $ 1  => -- put (.) infix
(*3) (1 + 100)     => -- apply (+100)
(1 + 100) * 3         -- apply (*3)

То есть, fmap для функций составляет их справа налево (точно так же, как (.), что разумно, потому что это (.)).

Чтобы посмотреть на это другим способом (для (двойного) подтверждения!), мы можем использовать подпись типа:

-- general fmap
fmap :: Functor f => (a -> b) -> f a -> f b

-- specialised to the function functor (I've removed the last pair of brackets)
fmap :: (a -> b) -> (r -> a) -> r -> b 

Итак, сначала значение типа r (третий аргумент) необходимо преобразовать в значение типа a (посредством функции r -> a), так что функция a -> b может преобразовать ее в значение типа b (результат).

Ответ 3

Нужно определить, как это сделать. Как вы указали, тип fmap:

fmap :: Functor f => (a -> b) -> f a -> f b

Рассмотрим случай, когда функтор f есть ((->) c)

( Примечание: нам бы хотелось написать это как (c ->), т.е. функции из c, но Haskell не позволяет нам это делать.)

Тогда f a на самом деле ((->) c a), что эквивалентно (c -> a), и аналогично для f b, поэтому имеем:

fmap :: (a -> b) -> (c -> a) -> (c -> b)

то есть. нам нужно взять две функции:

  • f :: a -> b
  • g :: c -> a

и постройте новую функцию

  • h :: c -> b

Но есть только один способ сделать это: сначала нужно применить g, чтобы получить что-то типа a, а затем применить f, чтобы получить что-то типа b, а это значит, что вам нужно определить

instance Functor ((->) c) where
    fmap f g = \x -> f (g x)

или, более лаконично,

instance Functor ((->) c) where
    fmap = (.)

Ответ 4

fmap для (->) определяется как fmap = (.). Итак, (fmap f g) x - (f . g) x - f (g x). В вашем случае (*3) ((+100) 1), что равно 3 * (100 + 1), что приводит к 303.

Ответ 5

fmap :: Functor f => (a -> b) -> f a -> f b

Помните, что f также может быть конструктором типа. Я полагаю, что это означает (для простейших случаев), что функция принимает что-то типа a, завернутое в f, и преобразует его в нечто вроде b, завернутое в f, используя функцию a -> b.

Во втором примере вы делаете (fmap show Just) 1. Это тип

Prelude> :t fmap show Just
fmap show Just :: (Show a, Functor ((->) a)) => a -> String

Это отличается от предыдущего

Prelude> :t fmap show (Just 1)
fmap show (Just 1) :: Maybe String

Разница в том, что в первом Just является конструктором типа, тогда как Just 1 является экземпляром типа. fmap является подходящим общим, так что он имеет значения для обоих.

Ответ 6

Чтобы сформировать тип функции, вам нужны 2 вида параметров для (- > ), то есть тип входных аргументов и тип возвращаемого значения.

Функтор может принимать только один параметр типа, поэтому вам нужно прибить тип входного аргумента (так как он первый слева направо), что делает возвращаемый тип функции параметром типа Functor.

Итак, для функции (Functor) a- > b вам нужно дать fmap функцию ff типа b- > xxx, отличную от a- > xxx, и это означает, что функция ff может применяться только после → b.