2014-11-16 2 views
7

Я только начал изучать Haskell, и одна из странных вещей для меня - это синтаксис для типа функции с несколькими аргументами.Почему Haskell использует стрелки для типа функции?

Рассмотрим простой пример:

(+) :: Num a => a -> a -> a 

Почему мы должны все стрелки здесь? Разве не было бы смысла писать что-то вроде Num Num Num -> Num?

В чем причина под капотом? Я искал этот вопрос, но не нашел ничего полезного.

+0

Что бы вы написали, если бы у вас был '(Ord a, Num a) => a -> a -> a'? – Squidly

ответ

16

Первое, что путает вещи, это Num a =>, поэтому мы сейчас будем игнорировать это. Вместо этого давайте рассмотрим Int -> Int -> Int, что является одной из возможных специализаций подписи типа, которую вы дали.

Функции почти всегда curried в Haskell. Это означает, что функция с несколькими аргументами фактически является функцией одного аргумента, который возвращает функцию, которая принимает следующий аргумент, и так далее.

-> является правильным ассоциативным, поэтому Int -> Int -> Int - это то же самое, что и Int -> (Int -> Int).

Это также означает, что это определение

f :: Int -> Int -> Int 
f x y = x + y 

такая же, как

f :: Int -> Int -> Int 
f x = \y -> x + y 

На самом деле, все функции в Haskell взять ровно один аргумент. Также существуют кортежи, но они являются первоклассными гражданами, поэтому они больше, чем просто список аргументов.

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

(+) метод является членом класса Num типа, так что вы должны ограничить a таким образом, чтобы использовать (+). Если вы попытаетесь дать f подпись a -> a -> a (без ограничений), это не сработает, потому что a полностью не имеет ограничений, и мы ничего не знаем о том, какие типы это могут быть. В результате мы не смогли использовать (+).

+0

+1 для ссылки! – CSnerd

0

Тип каждого аргумента в сигнатуре типа функции может содержать пробелы, поэтому скорее всего требуется разделитель без пробелов, поэтому компилятор (и люди!) Может различать их.

Например, вы можете иметь параметризованный абстрактный тип данных:

data MyType a = MyValue a 

и функцию, которая принимает конкретные типы (построенную из конструктора по MyType типа):

myFunc :: MyType Int -> MyType Int -> String 

Если вы Ждете» t есть -> между аргументами, подпись будет выглядеть как

myFunc :: MyType Int MyType Int -> String -- Not valid code 

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

+0

Я сомневаюсь, что вы поняли вопрос. Он спрашивает, почему haskell использует 'A -> B -> C' вместо' A B -> C'. То есть: что находится слева от '->' - это список аргументов, а справа - тип возвращаемого значения. – Shoe

+0

@ Джеффри. Ты прав, я пропустил это. Я немного изменил свой ответ. –

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