2016-06-29 2 views
4

Я только начинаю изучать Haskell, и я использую в качестве руководства learnyouahaskell.com, и я использую ghci в качестве интерпретатора. У меня вопрос о списках. На веб-сайте они указывают функцию:Как обобщать ввод в Haskell

boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x] 

Это работает только для списков. В то время как

boomBangs x = [ if x < 10 then "BOOM!" else "BANG!" | odd x] 

работает только для отдельных входов, т.е.

boomBangs 21 
boomBangs 7 

Есть ли способ, чтобы написать это заявление так, что это не имеет значения, положил ли я

boomBangs [2,5,6,7,1] 

или

boomBangs 7 

без необходимости утверждение if?

+2

Короткий ответ: нет. Haskell нуждается в вас, чтобы определить тип скважины для каждого входа, но есть способы обойти. – AJFarmar

+1

есть способ (создание экземпляра 'Num' для списка - так, чтобы буквальный' 7' был переведен в '[7]'), - но я бы не рекомендовал его – Carsten

+3

Есть разные причудливые трюки типа я бы не стал рекомендовать. – dfeuer

ответ

5

В общем, Haskell не позволяет вам произвольно перегружать одно и то же имя функции несколькими различными реализациями. Существуют языки программирования, которые позволяют вам это делать; Хаскелл не один из них.

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

Я понимаю, что это только для экспериментов, но я второй комментарий dfeuer: что такое boomBangs Предполагается, что означает? Какие типы аргументов он делает имеют смысл? Ну, очевидно, в этом случае boomBangs является тривиальной примерной функцией и на самом деле не имеет большого смысла ни для чего, кроме как для примерной функции. (Я не уверен, если вы даже попали в класс тип части урока еще.)

Обратите внимание, что, как написано, boomBangs является уже полиморфный: Это будет работать для любого типа целого числа , Он работает для подписанных 8-битных целых чисел, неподписанных 8-битовых целых чисел, 16-разрядных 16-битных целых чисел, неподписанных 16-битных целых чисел, целых чисел произвольной точности ... Таким образом, он работает для совсем немного вещей.

Обеспечение его работы для списков и не-списков не очень естественное обобщение этой функции. (В конце концов, это стрела s.) может имеет смысл обобщить его для работы для других складных объектов (например, список, Maybe, Either e). Это может также иметь смысл для работы на любой монаде (например, похоже, что небольшая настройка этого может работать для вычислений с учетом состояния или парсеров или действий ввода-вывода). Но опять же, я не знаю, было ли еще какое-либо из этих понятий введено в учебнике.

5

Да. Назовите вторую функцию по-другому: boomBang. Затем напишите boomBangs [2,5,6,7,1] или boomBang 7 - не требуется if.

Написание кода должно быть простым и естественным, не затрудняйте себя, чем это должно быть.

Теперь у вас есть

boomBangs xs = [b | x <- xs, b <- boomBang x] 

удаления дублирования кода, который обычно является признаком недоизученных проблемы пространства.

+0

сторона примечание: '[b | x <- xs, b <- boomBang x] '==' concat [boomBang x | x <- xs] '==' concatMap boomBang xs' == 'xs >> = boomBang'. –

2

Вы можете реализовать различные типы поведения для разных типов с использованием классов типов. Например:

class BoomBang a where 
    boomBang :: a -> [String] 

instance BoomBang Integer where 
    boomBang x = [if x < 10 then "BOOM" else "BANG" | odd x] 

instance BoomBang a => BoomBang [a] where 
    boomBang xs = xs >>= boomBang 

В GHCI:

> boomBang 7 
["BOOM"] 
> boomBang [2,5,6,7,1] 
["BOOM","BOOM","BOOM"] 
+0

и 'boomBang [[[2,5,6], [7,1]], [[19]]]' ==> '[" BOOM "," BOOM "," BOOM "," BANG "]' ! –

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