Что означает подпись типа "f (a -> b)" в Haskell? - PullRequest
3 голосов
/ 20 апреля 2020

Я пытаюсь понять аппликативы в Haskell. Не могу понять, что означает следующая подпись типа:

f (a -> b)

Например:

foo :: Num a => Maybe (a -> a)
foo = Just (+1)

Как понять значение Maybe (a -> a)? Это функция? Если да, то какие типы аргументов разрешены? Также очевидно, что я новичок в функциональном программировании, буду благодарен за любые ресурсы по этой теме c.

Ответы [ 2 ]

4 голосов
/ 21 апреля 2020

В функциональном программировании функции не так сильно отличаются от чисел или любых других значений. На самом деле единственное отличие состоит в том, что вы используете функцию для применения к аргументу.

Значение типа Maybe a является либо значением Nothing, либо Just x, где x имеет тип a. Поэтому, если у вас есть значение типа Maybe (a -> a), например, ваше foo, это либо Nothing, либо Just f, где f - это функция a -> a. В наименьшей степени причудливой, вы бы использовали это так:

case foo of
    Nothing -> "There was no function"
    Just f -> "There was a function, and its value at 0 is " ++ show (f 0)

Так что, если окажется, что foo не Nothing, тогда он содержит Just функцию в качестве значения.


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

data Iso a b = Iso (a -> b) (b -> a)

Iso даже не Functor (предварительное условие Applicative), но это все еще весьма полезно. Оказывается, что пары эквивалентны функциям из Bool. Мы могли бы построить такую ​​эквивалентность как Iso значение:

pairEquiv :: Iso (a,a) (Bool -> a)
pairEquiv = 
    Iso (\(x,y) -> \b -> if b then x else y) -- from pair to function
        (\f -> (f True, f False))            -- from function to pair

Здесь (Bool -> a) появляется в качестве аргумента для конструктора типа, и это просто означает, что если вы дадите Iso пару, он вернет вам функцию, и наоборот.

2 голосов
/ 21 апреля 2020

Вы можете представить f (a -> b) как функцию типа a -> b, заключенную в контекст. В основном это используется в контексте Applicative с, что Maybe a является ярким примером для.

Applicative с является расширением Functor с. Типичным примером использования Applicative являются функции с несколькими аргументами.

Что если у нас есть два Maybe Int, которые мы хотим сложить. Мы могли бы попытаться частично применить + с fmap aka <$>. Таким образом, мы можем попытаться:

f :: Maybe (Int -> Int)
f = (+) <$> Just 3

Но теперь, как мы применим это ко второму аргументу. Вот где нам нужен класс типов Applicative. Он определяет функцию <*>. Он имеет тип

<*> :: Applicative f => f (a -> b) -> f a -> f b

Таким образом, мы можем использовать его, чтобы применить секунду Maybe Int к нашей частично примененной функции f, выполнив:

> f <*> Just 4
Just 7

Без вспомогательной функции f синтаксис напоминает стандартное применение функции:

> (+) <$> Just 3 <*> Just 4
Just 7

Для получения дополнительной информации см. Главу о аппликативных функторах Изучения haskell.

...