fibs :: [Int]
fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)]
Це генерує послідовність Фібоначчі.
Я розумію поведінку охоронців :
, zip
і tail
, але я не розумію <-
. Що він тут робить?
Відповіді:
13 за відповідь № 1Завдяки позитивним голосам я зробив свій коментар відповіддю.
Те, що ви бачите, не є охоронцем, але воно є усвідомлення списку. Для початку подумайте про це як про спосіб виразити aматематичні позначення набору, такі як A = {x | x елемент N}, що означає щось на зразок: Множина A - це множина всіх натуральних чисел. У розумінні списку це було б [x | x <- [1..] ]
.
Ви також можете використовувати обмеження на свої номери: [x | x <- [1..], x `mod` 2 == 0 ]
та багато іншого.
Існує безліч хороших туроріалів Haskell, які охоплюють розуміння списку та навіть питання StackOverflow щодо ресурсів Haskell.
10 за відповідь № 2
Єдина хитра річ - zip fibs (tail fibs)
. zip
просто робить попарний список з кожного з своїх аргументів. Отже, якщо у вас є два таких списки:
[ 1, 2, 3, 4 ]
[ "a", "b", "c", "d" ]
Застібнувши їх, ви отримаєте:
[ (1,"a"), (2,"b"), (3,"c"), (4,"d") ]
Стрілка вліво (присвоєння шаблону деструктуризації) просто витягує парні елементи, щоб їх можна було скласти. Два списки, які архівуються, є fibs
і (tail fibs)
- іншими словами, послідовність Фібоначчі тапослідовність Фібоначчі, зміщена на 1 елемент. Хаскелл оцінюється ліниво, тому він може обчислити список, скільки б не потрібно було багато елементів. Це стосується і поштового індексу.
3 для відповіді № 3
Давайте розширимо його.
zip
створює пари із вмісту двох списків. Отже перша пара zip fibs (tail fibs)
дає нам є (0, 1)
, що складає до 1. Отже, тепер список є [0,1,1]
. Тепер ми знаємо три елементи у списку, тому розуміння списку можна продовжувати, захоплюючи наступний пункт зі списку та наступний елемент із хвоста, що дає (1,1)
- складаються, складаючи 2. Тоді отримуємо наступну пару, яка є (1,2)
, роблячи наступне число в послідовності 3. Це може тривати нескінченно, оскільки розуміння завжди забезпечить достатню кількість елементів.
2 для відповіді № 4
Однією з переваг функціонального програмування є те, що ви можете оцінити вираз від руки, ніби це математична задача:
fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)]
= 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] (tail [0, 1, ??])]
Ось тут ??
- частина, яка ще не оцінена. Ми будемо заповнювати його, як ми продовжуємо.
= 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] [1, ??])]
= 0 : 1 : [ a + b | (a, b) <- (0, 1) : zip [1, ??] [??]]
Зауважте, що я приховую оцінку zip
оскільки його визначення тут не наводиться, а деталі насправді не є загальними для поточного питання. Це позначення, яке я буду використовувати, щоб показати кожну пару чисел, створену zip
і поглинається розумінням списку.
= 0 : 1 : 0+1 : [ a + b | (a, b) <- zip [1, ??] [??]]
= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]]
Тепер ми знаємо, що наступний елемент у ??
це 1
:
= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]]
= 0 : 1 : 1 : [ a + b | (a, b) <- (1, 1) : zip [1, ??] [??]]
= 0 : 1 : 1 : 1+1 : [ a + b | (a, b) <- zip [1, ??] [??]]
= 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, ??] [??]]
І наступним елементом є 2:
= 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, 2, ??] [2, ??]]
Промити і повторити.
1 для відповіді № 5
Розуміння списку в дужках:
[ a + b | (a, b) <- zip fibs (tail fibs)]
повертає список, що містить вихідні дані (a + b), де змінні a і b походять з результату
zip fibs (tail fibs)
1 для відповіді № 6
Для чого це варто, мені здається, що наступну версію легше зрозуміти:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
0 для відповіді № 7
Він визначає цю діаграму потоку
.----->>------->>----.
/
/ /
/
<---- 0 <---- 1 ---<<--- (+)
/
/
*---->>------*
що витягує новий вхід із себе таким, яким він євиробляється, але завжди на одну і дві позиції перед виробничим пунктом, зберігаючи два "зворотні вказівники" в послідовності як би Це відображено у визначенні fibs = 0:1:[ a+b | a <- fibs | b <- tail fibs]
, з паралельним розумінням списку (:set -XParallelListComp
тощо).
Оскільки він використовує лише свій останній два елементів, це еквівалентно
map fst . iterate ((a, b) -> (b, a+b)) $ (0,1)
-1 для відповіді № 8
Як аналізатор міг би знати, що потрапляє в (а, б) інакше?
EDIT: Завдяки ViralShah я зроблю це трохи менш гномічним. Символ "<-" говорить парсеру призначити список пар з правого боку "zip fibs (tail fibs)" до лівого боку "(a, b)".
-1 для відповіді № 9
я все ще не розумію. мені подобається така відповідь: https://stackoverflow.com/a/42183415/246387 (від код-учень)
але я не розумію, як з цього рядка:
= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]]
воно переходить до цього:
= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]]
і крім цього, у мене є ще щось, що мене турбує:
як я можу використовувати fib
всередині списку-розуміння, якщо я цього не маю fib
взагалі (так здається, але впевнений, що я "помиляюся), тому що fib
ще не розраховано. він "чекає" (у лівій частині знака рівності) для обчислення в правій стороні (знака рівності).