Одно из преимуществ, которые я получаю от того, чтобы сделать мои функции максимально возможными, заключается в том, что он часто позволяет использовать случаи, о которых я раньше не думал. Когда вы начинаете делать вещи вообще, вы начинаете придумывать странные способы использования своих функций.
Вы идете: «Но что, если это значение является функцией?» Или «Что, если я разрешу это для любого функтора, что будет результатом для других функторов? Полезно ли это?» Как оказалось, это во многих случаях! И это одна из причин, по которой Хаскелл настолько велик, на мой взгляд. Легко «случайно» создавать очень многократно используемые функции.
На других языках вы разрабатываете функции для определенных целей и используете их таким образом. В Haskell вы разрабатываете функции для определенных целей и даете им общую подпись типа, и вдруг они работают в тонне случаев, для которых вы их не проектировали.
@jozefg сделал отличную оценку общности, ограничивающей возможные реализации. Я просто хочу дать больше внимания, потому что это на самом деле очень мощная концепция. С помощью нескольких общих функций вы можете быть абсолютно уверены, что функция работает только на основе сигнатуры типа, потому что для этой общей подписи существует только одна возможная реализация.
Недавно я столкнулся подпись
mystery :: (a -> b -> c) -> (a -> b) -> a -> c
, который интересен тем, что мы можем на самом деле выяснить, какую функцию она основана на том, что он делает. У нас есть
mystery :: (a -> b -> c) -> (a -> b) -> a -> c
mystery f g x = ...
, и мы должны это вернуть c
значение некоторого типа. Единственным способом получить значение типа c
является применение функции f
к значению a
и значению b
. У нас уже есть одно значение a
- это аргумент x
. Поэтому мы можем частично применить f x :: b -> c
, но нам все равно нужно значение b
, чтобы получить желаемое значение c
.
Решение, конечно, применять g x
получить значение b
, который мы затем можем придерживаться в f
, таким образом, в конце концов возвращает значение c
. Описание это немного сложно следовать, но если вы работаете с ним в вашей голове вы прибудете на
mystery f g x = f x (g x)
, который выполняет то же самое, что и функция библиотеки ap
. (От Control.Applicative
.)
Это очень круто, что вы можете понять, что функция делает исключительно на основе ее подписи!
Это может вам помочь: http://stackoverflow.com/questions/17100036/should-i-use-typeclasses-or-not?rq=1 – Sibi
Подумайте о свойствах функции/args. Какие свойства вы хотите использовать в своей функции/args ?. Во-первых, поймите о свойствах ('Eq',' Ord', 'Monoid', ...), тогда вы можете ограничить свои функции работой * с аргументами (свойствами соответствия) * (вместо явных аргументов, таких как' Int', ' Bool', ...). – josejuan
'factorial' на самом деле плохой пример, потому что если вы используете' Int' вместо 'Integer', он дает неправильный ответ для любого числа выше 20. –