Haskell, список натуральных чисел - PullRequest
10 голосов
/ 21 марта 2010

Я абсолютный новичок в Хаскеле, но пытаюсь понять, как это работает.

Я хочу написать свой собственный ленивый список целых чисел, например [1,2,3,4,5 ...].

Список тех, что я написал

ones = 1 : ones

и при попытке работает нормально:

*Main> take 10 ones
[1,1,1,1,1,1,1,1,1,1]

Как я могу сделать то же самое для увеличения целых чисел?

Я пробовал это, но это действительно не удается:

int  = 1 : head[ int + 1]

И после этого, как я могу создать метод, который умножает два потока? такие как:

mulstream s1 s2 = head[s1] * head[s2] : mulstream [tail s1] [tail s2]

Ответы [ 4 ]

21 голосов
/ 21 марта 2010

Причины, по которым int = 1 : head [ int + 1] не работает:

  • head возвращает один элемент, но вторым аргументом : должен быть список.
  • int + 1 пытается добавить список и номер, что невозможно.

Самый простой способ создать список с 1 до бесконечности - это [1..]

Для подсчета шагов, отличных от 1, вы можете использовать [firstElement, secondElement ..], например, создать список всех положительных нечетных целых чисел: [1, 3 ..]

Чтобы получить бесконечные списки вида [x, f x, f (f x), f (f (f x)),...], вы можете использовать iterate f x, например, iterate (*2) 1 вернет список [1, 2, 4, 16,...].

Чтобы применить операцию попарно к каждой паре элементов из двух списков, используйте zipWith:

mulstream s1 s2 = zipWith (*) s1 s2

Чтобы сделать это определение более кратким, вы можете использовать форму без очков:

mulstream = zipWith (*)
17 голосов
/ 21 марта 2010

Для натуральных чисел вы должны использовать карту:

num1 = 1 : map (+1) num1

Или понимания:

num2 = 1 : [x+1 | x <- num2]

Или, конечно:

num3 = [1..]
4 голосов
/ 21 марта 2010

Я не уверен, что это то, о чем вы спрашивали, но мне показалось, что вы хотите составить список растущих натуральных чисел, не полагаясь на какой-либо другой список. Таким образом, вы можете делать такие вещи, как

incr a = a : inrc (a+1)
lst = inrc 1

take 3 lst
=> [1,2,3]

Это, технически, называется накопительной функцией (я полагаю), и тогда все, что мы сделали, - это сделали специальный случай, который легко использовать с помощью 'lst'

Вы можете сойти с ума, делая такие вещи, как:

lst = 1 : incr lst where incr a = (head a) + 1 : incr (tail a)

take 3 lst
=> [1,2,3]

и так далее, хотя это, вероятно, основывается на некоторых вещах, которые вы еще не узнали (где) - судя по ОП - но это все равно должно читаться довольно легко.

Да, верно, а затем умножение списка. Ну, вы можете использовать zipWith (*), как упомянуто выше, или вы можете изобрести колесо вот так (это веселее, поверьте мне:)

lmul a b = (head a * head b) : lmul (tail a) (tail b) 
safemul a b = take (minimum [len a, len b]) (lmul a b)

Причину safemul, я полагаю, вы можете выяснить, поэкспериментировав с этой функцией, но это связано с «tail». Проблема в том, что нет пустого списка, несоответствующих списков и т. Д., Поэтому вам придется либо взламывать различные определения (lmul _ [] = []), либо использовать охранники и / или где и так далее. ... или придерживаться zip с:)

2 голосов
/ 21 марта 2010

Существует синтаксис для этого в языке:

take 10 [1,2..]

=> [1,2,3,4,5,6,7,8,9,10]

Вы даже можете делать разные шаги:

take 10 [1,3..]
=> [1,3,5,7,9,11,13,15,17,19]
...