4

Я пытаюсь изучить немного Haskell с онлайн-книгой «Учите вас Haskell», и у меня есть вопрос о функциях более высокого порядка.Сравнение шаблонов с функциями (более высокого порядка) в Haskell

some examples Я видел, и я хочу сделать еще несколько дополнительных функций, но я не знаю, почему я всегда читал следующее исключение:

*** Исключение: euler13.hs: (11,0) - (15,39): неисчерпывающая модель в функции применяется

и функции я определил это один:

apply :: (Num b, Ord b) => (a -> a) -> b -> [a] -> [a] 
apply f n [] = [] 
apply f n [x] 
    | n <= 1 = map f [x] 
    | otherwise = apply f (n-1) (map f [x]) 

Я хочу к pply 'n' умножает на конкретную функцию, называемую 'f', на список '[x]'. Я попытался сделать эту функцию полиморфной, поэтому тип параметра «a». Но я тоже хочу использовать числа и списки, поэтому я непосредственно использую список (если я хочу использовать функцию только для числа, это будет [число] очевидно)

Может ли кто-нибудь помочь мне, пожалуйста? Мне нравится этот язык, но это немного сложно, когда вы учитесь, потому что это так отличается от Java или c (например)

Спасибо!

+0

Предлагаю переименовать заголовок вопроса: это проблема с сопоставлением шаблонов, не обязательно с функциями более высокого порядка. –

+0

Хорошо, все сделано. Это прямо сейчас? Благодаря! – albertoblaz

ответ

13

Удалите [] вокруг x. В противном случае 2-й шаблон может соответствовать только спискам только с 1 элементом.

apply f n x 
    | n <= 1 = map f x 
    | otherwise = apply f (n-1) (map f x) 
+8

И пока мы на нем: переименуем его в 'xs', более общее имя для« списка чего угодно ». – delnan

+0

Да, это правда. Проблема в том, что я пытался многое сделать, делая изменения и больше изменений, и ничего. Но правильным является использование «xs» – albertoblaz

5

apply определяются для двух случаев: п и пустой список и п и список из одного элемента. Что происходит, когда список содержит более одного элемента? Это недостающий шаблон.

11

Это ничем не отличается от того, что говорили другие, но, возможно, дело должно быть трудным? Существуют два основных «конструктора» для списков и, следовательно, два основных случая, которые вам необходимо учитывать при определении функций из списков: аргументы формы [] и (:). последний, (:) может присоединиться ко всему со списком такого рода вещей, таким образом 1 с [] - 1:[] или [1]. Или он может присоединиться к 1 с чем-то вроде этого: 1:(1:[]) i.e. 1:[1], т. Е. [1,1] как специальный синтаксис позволяет нам писать.

Было бы более очевидным, что бы то пошло не так, если бы вы определили списки сами, написав:

data List a = Nil | Cons a (List a) deriving (Show, Eq, Ord) 

Использование [] и x:xs просто хвастовство сахара что-то вроде этого. Аналогично, специальный сахар String позволяет нам писать "abc", а не ['a','b','c'], что намного лучше, чем 'a':'b':'c':[]. (С приведенным выше определением нам нужно было бы написать Cons 'a' (Cons 'b' (Cons 'c' Nil))), что немного для короткой строки! - хотя это также объясняет, почему следует предпочесть ByteString и Text представления строк для многих целей.) При более подробном определении списка, как это, нам нужно добавить наши собственные map (или, вернее, fmap), таким образом, мы можем сказать,

instance Functor List where 
    fmap f Nil = Nil 
    fmap f (Cons first rest) = Cons (f first) (fmap f rest) 

Обратите внимание, что при определении fmap для этого случая я должен был рассмотреть оба типа конструктора для моего типа списка, Nil и Cons first rest (или Cons x xs, как это часто написано).

Или, может быть, вы еще не встал на общее обсуждение класса Functor типа в Лях - в этом случае, просто считайте, что вы можете определить свой собственный map, как

listMap f Nil = Nil 
listMap f (Cons first rest) = Cons (f first) (listMap f rest) 

В любом случае, учитывая это Обессахаренный переписывают типа списка, ваше фактическое определение функции будет:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a 
apply f n Nil = Nil 
apply f n (Cons first Nil) 
    | n <= 1 = fmap f (Cons first Nil) -- or listMap f (Cons first Nil) 
    | otherwise = apply f (n-1) (fmap f (Cons first Nil)) 

случаев вы покрыли являются:

apply f n Nil 
apply f n (Cons first Nil) 

Cons first Nil такое же, как first : [] или [first] - i.e. [x], как вы его пишете. Но это означает, что вы не охватили все случаи, ваше определение «не является исчерпывающим». Вы не указали, как применять f и n к списку, если у него более одного члена. Что, если список имеет форму Cons x (Cons y Nil) или Cons x (Cons y (Cons z Nil)), а не Nil (ваша первая строка) или Cons x Nil (ваша вторая строка)?

Решения, как другие говорили, или с помощью нашего Обессахаренного списка типа:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a 
apply f n Nil = Nil 
apply f n (Cons first rest) 
    | n <= 1 = fmap f (Cons first rest) 
    | otherwise = apply f (n-1) (fmap f (Cons first rest)) 

Здесь «переменная» rest охватывает все списки, Nil или нет. Таким образом, мы получаем:

*Main> apply (+1) 3 Nil 
Nil 
*Main> apply (+1) 3 (Cons 3 Nil) 
Cons 6 Nil 

, как вы бы, но также:

*Main> apply (+1) 3 (Cons 0 (Cons 1 (Cons 2 Nil))) 
Cons 3 (Cons 4 (Cons 5 Nil)) 
+0

Поистине впечатляет весь ответ. Спасибо, что объяснил мне. Да, я не получил эту роль в ЛЯХ. Единственное, что я не понял, - это то, почему вы определили свою собственную функцию «map» и почему вы использовали Nil и Cons вместо [] и:? Я думаю, что sytantic sugar легче использовать. В любом случае, спасибо за ваш ответ! – albertoblaz

2

Это не новый ответ, по сравнению с другими данными, но, надеюсь, проницательные, тем не менее.

Вы уже продемонстрировали некоторое понимание соответствия шаблонов в определениях функций; когда первый шаблон не соответствует, оценка переходит к следующему. Шаблоны, которые могут не совпадать, считаются «опровержимыми».

Как правило, это хорошая идея, чтобы ваше определение последней функции было «неопровержимым», что означает, что оно всегда совпадает. От Haskell 2010 report:

неопровержимого узоров заключается в следующем: переменном, групповом символе, N APAT, где N представляет собой конструктор, определенный с помощью Newtype и APAT неопровержим, вар @ APAT, где APAT неопровержимо, или формы ~ APAT. Все остальные образцы опровержимы.

Вашего непонимание, что вы думали, [x] переменные (неопровержимый образец), когда на самом деле опровержим шаблон (шаблон для списка одного элемента, который связывает x к этому одному элементу).

Предположим, вы написали функцию, которая работает только в списках длины 3. Если вы хотите получить более описательное сообщение об ошибке, чем «неисчерпывающие шаблоны», вы можете использовать неопровержимый шаблон подстановочного знака (подчеркивания). Тривиальный пример:

sum3 [x,y,z] = x+y+z 
sum3 _  = error "sum3 only works on lists of length 3" 
+0

О, хорошо это знать. На самом деле, я изучаю этот язык в свободное от работы время, а не в университете, поэтому я до сих пор не очень разбираюсь в Haskell, но хорошо изучить некоторые методы и «хаки», подобные вышеупомянутому. – albertoblaz

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