Составьте список в haskell с помощью let и покажите, для чего он нужен? - PullRequest
0 голосов
/ 18 мая 2018

Я изучаю проектные решения Эйлера, и это решение задачи 4, в котором нужно

Найти самый большой палиндром из произведения двух трехзначных чисел

problem_4 =
  maximum [x | y<-[100..999], z<-[y..999], let x=y*z, let s=show x, s==reverse s]

Я понимаю, что этот код создает список такой, что x является продуктом всех возможных z и y.

Однако у меня проблемы с пониманием того, что s делает здесь.Похоже, все после | будет выполняться каждый раз, когда нужен новый элемент из этого списка, верно?

Не думаю, что понимаю, что здесь происходит.Не должно ли все, что справа от | быть ограничением?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Понимание списка - это довольно тонкая оболочка вокруг выражения do:

problem_4 = maximum $ do
     y <- [100..999]
     z <- [y..999]
     let x = y*z
     let s = show x
     guard $ s == reverse s
     return x

Большинство произведений переведены напрямую;части, которые не являются итераторами (<-) или let выражениями, обрабатываются как аргументы функции guard, найденной в Control.Monad.Эффект guard заключается в коротком замыкании оценки;для монады списка это означает, что не выполняется return x для конкретного значения x, которое привело к ложному аргументу.

0 голосов
/ 18 мая 2018

Не думаю, что понимаю, что здесь происходит. Не должно ли все, что справа от | быть ограничением?

Нет, в правой части вы видите выражение, которое представляет собой разделенный запятыми (,) список «частей», и каждая часть представляет собой одно из следующего дерева:

  1. «генератор» формы somevar <- somelist;
  2. a let оператор , который является выражением, которое может использоваться, например, для представления переменной, которая хранит подрезультат; и
  3. выражения типа boolean, действующие как filter .

Так что это не своего рода " программирование с ограничениями ", где можно просто перечислить некоторые ограничения и надеяться, что Хаскелл это выяснит (на самом деле, лично в этом заключается разница между "языком программирования" и «язык спецификации»: на языке программирования вы «управляете» тем, как данные передаются на языке спецификации, который обрабатывается системой, которая читает ваши спецификации)

По сути, итератор можно сравнить с циклом «foreach» во многих императивных языках программирования. Выражение «let» можно рассматривать как представление временной переменной (но учтите, что в Haskell вы не присваиваете переменную, вы объявляете их, поэтому вы не можете переназначать значения). Фильтр можно рассматривать как оператор if.

Таким образом, понимание списка было бы эквивалентно чему-то в Python вроде:

for y in range(100, 1000):
    for z in range(y, 1000):
        x = y * z
        s = str(x)
        if x == x[::-1]:
            yield x

Таким образом, мы сначала итерируем по двум диапазонам вложенным способом, затем объявляем x умножением y и z, при let s = show x мы в основном конвертируем число (например, 15129 ) к его строковому аналогу (например, «15129»). Наконец, мы используем s == reverse s, чтобы перевернуть строку и проверить, равна ли она исходной строке.

Обратите внимание, что существуют более эффективные способы проверки палиндромов, особенно для умножения двух чисел.

...