Haskell, список натуральных чисел

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

Я хочу написать свой собственный ленивый список целых чисел, например [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]

person Hellnar    schedule 21.03.2010    source источник
comment
Вы можете быть смущены разницей между () и [], так как ваш последний пример работает (для бесконечных списков), если вы замените все [] на ().   -  person Reid Barton    schedule 21.03.2010


Ответы (4)


Причины, по которым 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 (*)
person sepp2k    schedule 21.03.2010

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

num1 = 1 : map (+1) num1

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

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

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

num3 = [1..]
person Łukasz Lew    schedule 21.03.2010
comment
или также nat = 1 : map succ nat - person sastanin; 23.03.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]
person clord    schedule 21.03.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]

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

Ах да, а потом умножение списка. Ну, вы можете использовать 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, думаю, можно выяснить, поэкспериментировав с функцией, но она связана с «хвостом». Проблема в том, что нет случая для пустого списка, несоответствующих списков и т. д., поэтому вам либо придется собирать различные определения (lmul _ [] = []), либо использовать охранники и или где и т. д. ... или придерживайтесь zipWith :)

person Hiato    schedule 21.03.2010