haskell - пусть / где эквивалент в понимании списка? - PullRequest
14 голосов
/ 20 мая 2011

Есть ли способ использовать let, where или иным образом определять подвыражения в понимании списка, чтобы его можно было использовать как в терминах, так и в ограничениях?

Из моих экспериментовследующая работа:

[let x = i*i in x | i<-[1..10], i*i > 20]   --good
[i*i | i<-[1..10], let x=i*i in x > 20]     --good

Но это не bc of scope:

[let x = i*i in x | i<-[1..10], x > 20]  -- 'x' not in scope error
let x = i*i in [x | i<-[1..10], x > 20]  -- 'i' not in scope error
[x | i<-[1..10], x > 20] where x = i*i   --parse error on 'where'

Так что let работает в одном месте или в другом, но не в обоих вместе!

Единственный способ заставить его работать (то есть избежать повторных выражений и, возможно, вычислений) - добавить глупый одноэлементный список, как я это сделал здесь, с x<-[cat i [1..k] в качестве ограничения для понимания списка:

> let cat x l = foldl1 (++) $ map show [x*i | i<-l]
maximum [x| i<-[1..9999], k<-[2..div 10 $ length $ show i], x<-[cat i [1..k]], sort x == "123456789"]
"932718654"

Или, продолжая тривиальный пример, приведенный выше,

[x | i<-[0..10], x<-[i*i], x > 20] --works

Это кажется немного глупым и немного неясным, хотя и не слишком неэффективным.Тем не менее, было бы неплохо, если бы let или where работали во всем понимании.Можно ли это сделать?

Ответы [ 2 ]

24 голосов
/ 20 мая 2011

Вы пишете это так:

[x | i <- [0..10], let x = i*i, x > 20]

Обратите внимание, что нет in.Вы можете ссылаться на x как в термине, так и в любых ограничениях, следующих за let.Эта форма let соответствует форме в do -обозначении:

do i <- [0..10]
   let x = i*i
   guard (x > 20)
   return x

Здесь x находится в области от let до конца do -блока.

5 голосов
/ 20 мая 2011

У тебя почти было это;Вы можете просто написать [x | i <- [0..10], let x = i*i, x > 20] (обратите внимание на , вместо in).Это очень похоже на примечание do (на самом деле вы можете использовать вместо него примечание do, а недавнее расширение GHC позволяет использовать списочные выражения для произвольных монад).Если вам интересно, вы можете найти синтаксис в отчете Haskell 98 :

aexp -> [ exp | qual_1 , ... , qual_n ] (list comprehension, n >= 1)
qual -> pat <- exp                      (generator)
     |  let decls                       (local declaration)
     |  exp                             (guard)

Как видите, один из допустимых квалификаторов - let decls, чточто ты хотел.

...