Comments 23
Haskell автоматически выполняет каррирование всех функций, принимающих более одного параметра.Скорее, программист обычно выполняет каррирование всех функций, принимающих более одного параметра. Но можно и не выполнять. Так, функция, принимающая кортеж — это тоже, в некотором роде, функция нескольких параметров — при этом определение такой функции ничуть не сложнее определения каррированной функции.
add1 a b = a+b
add2 (a, b) = a+b
Что интересно, для получения одного из другого можно использовать встроенные функции curry и uncurry, что довольно удобно для выполнения всяких операций над парами.
Например,
Надо понимать, что функции эти действуют для двух аргументов, больше — либо самому писать, либо удовлетворяться встроенными, которые, впрочем, есть и для 3х аргументов: hackage.haskell.org/package/utility-ht-0.0.5.1/docs/Data-Tuple-HT.html
Например,
map (uncurry (+)) xs
превращает список пар в список их сумм.Надо понимать, что функции эти действуют для двух аргументов, больше — либо самому писать, либо удовлетворяться встроенными, которые, впрочем, есть и для 3х аргументов: hackage.haskell.org/package/utility-ht-0.0.5.1/docs/Data-Tuple-HT.html
В Haskell функции без параметров называются константными функциями, поскольку каждая из них всегда возвращает одно и то же значение.
Это неправильно. В Haskell нет функций без параметров. В сигнатуре функции (после всех возможных подстановок) всегда присутствует хотя бы одна стрелка; если это не так — то это не функция, это конкретное значение.
М. Липовача «Изучай Haskell во имя добра!», стр. 28:
Когда функция не принимает аргументов, говорят, что это константная функция.
Формально это всё биндинги и разницы нет.
На самом деле, этот вопрос сложнее, чем Вам кажется. Элиот посвятил этому вопросу целый пост, который я рекомендую к прочтению.
Googolplex прав насчёт того, что в Haskell нет функций без параметров. И этот вопрос не связан с тем, есть ли у выражения биндинг или нет. Не все функции являются биндингами. Не все значения являются биндингами. Эта формулировка вообще некорректна. Некоторые выражения связаны с именами. Некоторые — нет. Но у каждого выражения есть тип. При этом некоторые выражения имеют тип функции, другие — нет.
Думаю, Миран Липовача осознанно опускает различие между функциями и биндингами (см. «Mixing up functions and definitions» у Элиота). Мне кажется, что на стр. 28 книги для начинающих это вполне допустимо. Пусть человек «пощупает» язык, а в терминологии он разберётся и потом.
Googolplex прав насчёт того, что в Haskell нет функций без параметров. И этот вопрос не связан с тем, есть ли у выражения биндинг или нет. Не все функции являются биндингами. Не все значения являются биндингами. Эта формулировка вообще некорректна. Некоторые выражения связаны с именами. Некоторые — нет. Но у каждого выражения есть тип. При этом некоторые выражения имеют тип функции, другие — нет.
Думаю, Миран Липовача осознанно опускает различие между функциями и биндингами (см. «Mixing up functions and definitions» у Элиота). Мне кажется, что на стр. 28 книги для начинающих это вполне допустимо. Пусть человек «пощупает» язык, а в терминологии он разберётся и потом.
Благодарю за ссылку, почитаю. Мои заметки по Haskell — это изложение того, как я понял ту или иную тему в ходе её изучения. Я не исключаю, что какой-то материал мною мог быть понят неверно. Опубликовывая информацию по Haskell через призму своего текущего понимания, я тем самым ожидаю, что более опытные люди смогут аргументированно указать мне на мои ошибки (собственно ради этого и опубликовываю).
В книгах тоже иногда пишут фигню.
Что такое «конкретное значение» в данном контексте?
Экземпляр конкретного типа данных (Int, String, Bool, etc).
Как отличить конкретный тип данных от абстрактного? неконкретного?
М. Липовача «Изучай Haskell во имя добра!», стр 159:
Примечание. Мы называем тип конкретным, если он вообще не принимает параметров (например Int или Bool) либо если параметры в типе заполнены (например, Maybe Char). Если у вас есть какое-то значение, у него всегда конкретный тип.
Тогда противопоставление «функции» «конкретному значению» некорректно.
Все параметры в типе ''Int -> Bool'' заполнены. Следовательно, он является конкретным.
Все параметры в типе ''Int -> Bool'' заполнены. Следовательно, он является конкретным.
Тогда функция, это просто (->) (с аргументами, разумеется, так как сама стрелка имеет kind * -> * -> *), а всё остальное — не функция.
Т.е. это не функция:
Зато это — функция:
Т.е. это не функция:
Maybe (a -> b) -- == Maybe ((->) a b)
Зато это — функция:
a -> Maybe b -- == (->) a (Maybe b)
Это значит — константа, элемент из множества нефункционального типа:
Определение нефункционального типа, я полагаю, можно ввести так.
Функциональный тип — это экспоненциал в категории Hask. Соответственно, нефункциональные типы составляют дополнение функциональных типов до всего класса объектов Hask, т. е. это все те объекты, которые не являются экспоненциалами.
pi :: Double
pi = 3.14 // вещественная константа
printHello :: IO ()
printHello = putStrLn "Hello" // константа - IO-действие
Определение нефункционального типа, я полагаю, можно ввести так.
Функциональный тип — это экспоненциал в категории Hask. Соответственно, нефункциональные типы составляют дополнение функциональных типов до всего класса объектов Hask, т. е. это все те объекты, которые не являются экспоненциалами.
Тема бесточечной нотации вообще не раскрыта. Лучше было бы сделать пример каким-то таким:
И потом объяснить, что под точкой подразумевается совсем не знак композиции.
countEven :: Integral a => [a] -> Int
countEven = length . filter even
И потом объяснить, что под точкой подразумевается совсем не знак композиции.
Надо бы в сигнатуру добавить еще одну переменную типа
func :: (Num a) => a -> a -> a -> a
func a b c d = a + b + c + d
Sign up to leave a comment.
Немного о каррировании в Haskell