2015-12-07 3 views
20

Возьмите тип подписи fmap (Functor метод) в качестве примера:В чем смысл круглых скобок в подписях типа Haskell?

(a -> b) -> f a -> f b 

Как это отличается от следующего вида подписи?

a -> b -> f a -> f b 

Есть ли разница между этими двумя типами подписей?

+2

Как вопрос в тексте и вопрос в заголовке, связанных? Скобки в сигнатурах типа * не * обозначают специальную семантику, они для приоритета, как и везде в Haskell, поэтому два фрагмента * не * эквивалентны. –

+2

@ JörgWMittag: Я согласен, что два вопроса не являются * эквивалентными * - и на самом деле имеют разные ответы, но я удивлен, что вы находите их * несвязанными *. Они оба касаются значения круглых скобок в сигнатурах типов; ответ «да» на вопрос в названии, вероятно, повлечет за собой «да» ответ на вопрос в тексте; и хороший ответ на любой вопрос, вероятно, косвенно (или даже явно) отвечает на другой вопрос. – ruakh

+1

Скобки в титрах обозначают приоритет, как в терминах. Приоритет - это чисто синтаксическое свойство *, оно не имеет смыслового значения.Таким образом, круглые скобки в типах подписей не являются ни специальными, ни семантическими, а * that * - это то, почему два фрагмента не эквивалентны, так же как 'a + b * c' и' (a + b) * c' не эквивалентны, также потому, что синтаксического приоритета, а не из-за семантики. –

ответ

29

Да, есть разница, потому что the -> type constructor is right-associative. Другими словами,

a -> b -> f a -> f b 

эквивалентно

a -> (b -> (f a -> f b)) 

Этот тип подписи обозначает функцию, которая принимает параметр типа a и возвращает функцию, которая сама принимает параметр типа b и возвращает функция, которая сама принимает параметр типа f a и возвращает значение типа f b.

С другой стороны,

(a -> b) -> f a -> f b 

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

Вот надуманный пример, который иллюстрирует разницу между подписями на два типа:

f :: (Int -> Bool) -> [Int] -> [Bool] 
f = map 

g :: Int -> Bool -> [Int] -> [Bool] 
g n b = map (\n' -> (n' == n) == b) 

λ> let ns = [42, 13, 42, 17] 

λ> f (== 42) ns 
[True,False,True,False] 

λ> g 42 True ns 
[True,False,True,False] 

λ> g 42 False ns 
[False,True,False,True] 
13

Да,

(a -> b) -> ... 

означает "заданной функции, которая принимает к Ь ...". В то время как это

a -> b -> ... 

означает «учитывая некоторые а и некоторые б ...»

6

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

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