As I understand, the code
l = [(a,b)|a<-[1,2],b<-[3,4]]
is equivalent to
l = do
a <- [1,2]
b <- [3,4]
return (a,b)
or
[1,2] >>= (\a -> [3,4] >>= (\b -> return (a,b)))
The type of such expression is [(t,t1)] where t and t1 are in Num.
If I write something like
getLine >>= (\a -> getLine >>= (\b -> return (a,b)))
the interpreter reads two lines and returns a tuple containing them.
But can I use getLine or something like that in list generators?
The expression
[x|x<-getLine]
returns an error "Couldn't match expected type [t0]' with actual type
IO String'"
But, of course, this works in do-notation or using (>>=).
What's the point of list generators, and what's the actual difference between them and do-notation?
Is there any type restriction when using list gens?
That's a sensible observation, and you're not the first one to stumble upon that. You're right that the translation of [x|x<-getLine]
would lead to a perfectly valid monadic expression. The point is that list comprehensions were, I think, first only introduced as convenience syntax for lists, and (probably) no one thought that people might use them for other monads.
However, since the restriction to []
is not really a necessary one, there is a GHC extension called -XMonadComprehensions
which removes the restriction and allows you to write exactly what you wanted:
Prelude> :set -XMonadComprehensions
Prelude> [x|x<-getLine]
sdf
"sdf"
My understanding is that list comprehensions can only be used to construct lists.
However, there's a language extension called "monad comprehensions" that allows you to use any arbitrary monad.
https://ghc.haskell.org/trac/ghc/wiki/MonadComprehensions
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With