2015-01-09 3 views
1

Я аппликативный <$> оператор более или менее разобрался, но я не могу понять, подпись я получаю на следующем примере:

ghci> let f x y z = x + y + z -- f::Num a => a -> a -> a -> a 
ghci> f <$> Just 2 <*> Just 3 <*> Just 4 
Just 9 

Этот результат я понимаю, но при проверке следующих типов:

ghci> :t (<$> f) 
(<$> f) :: Num a => ((a -> a -> a) -> b) -> a -> b --This makes no sense to me 

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

(<$>f) f 4 

, который приведет к Integer. Очевидно, это неверно, так что вы можете помочь мне понять, как читать тип (<$> f)?

+5

Вы уверены, что вас не интересует тип '(f <$>)' вместо? Обратите внимание, что '(f <$>)' совпадает с '(<$>) f', то есть частичным применением' (<$>) 'к его первому аргументу, но' (<$> f) 'является частичным применением' (<$>) 'в свой * второй * аргумент. – kosmikus

+2

Оператор '<$>' - это просто псевдоним для 'fmap' из класса« Functor ». Я согласен с @kosmikus, что вы, возможно, хотели попробовать ': t (f <$>)' или, возможно, ': t (<$>) f' (они эквивалентны). – bheklilr

+0

Вы оба абсолютно правы, я искал '(f <$>)' !!! Но теперь мне остается удивляться, почему мои рассуждения не держатся, когда говорят о '(<$> f)', как читать его подпись? – Chirlo

ответ

3

функция, которая принимает (a -> a- > a) -> b функцию и a в качестве параметров и возвращает b.

Это правильно.

Согласно этой логике, я должен назвать это как:

(<$>f) f 4 

, который приведет к Integer.

Нет, потому что f не имеет типа (a -> a -> a) -> b или один совместимый с ним. Вместо этого он имеет тип Num a => a -> a -> a -> a. То есть f берет три числа и производит число, тогда как мы ищем функцию, которая принимает в качестве первого аргумента функцию (типа a -> a -> a).

+0

Я вижу, я не понял, что '(a -> a -> a)' является самой функцией! Так, например, '(<$> f) (\ g -> g 2 3) 4' удовлетворяет сигнатуре. Благодаря! – Chirlo

1

<$> принимает в качестве второго аргумента что-то типа g b, где g - любой прикладной функтор.

Вы передаете f :: Num a => a -> a -> a -> a в качестве второго аргумента. Давайте проигнорируем контекст Num a, чтобы все было просто.

Следовательно, мы ищем g,b такой, что g b = a -> a -> a -> a.

Напишем тип f в виде префикса:

f :: (->) a ((->) a ((->) a a)) = g b 

Следовательно, g = (->) a и b = ((->) a ((->) a a)). Последний - b = a -> a -> a в форме инфикса.

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

TL; DR: перегруженные идентификаторы могут преобразовывать многие вещи, адаптируясь к их контекстам, возможно, каким-то неожиданным образом.

Смежные вопросы