Это ничем не отличается от того, что говорили другие, но, возможно, дело должно быть трудным? Существуют два основных «конструктора» для списков и, следовательно, два основных случая, которые вам необходимо учитывать при определении функций из списков: аргументы формы []
и (:)
. последний, (:)
может присоединиться ко всему со списком такого рода вещей, таким образом 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))
Предлагаю переименовать заголовок вопроса: это проблема с сопоставлением шаблонов, не обязательно с функциями более высокого порядка. –
Хорошо, все сделано. Это прямо сейчас? Благодаря! – albertoblaz