List comprehension guard equivalent of filterMHaskell List Comprehensions guards in F#haskell - let/where equivalent within list comprehension?Haskell: Lists, Arrays, Vectors, SequencesFor a list comprehension in Haskell the equivalent in Scala?Using guards in list comprehensionsWhat are some better ways to write [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] in Haskell?List comprehension guardsGetting my bearings on state-monadic “uncurrying”Combining elements with probabilities in HaskellGuards in list comprehensions don't terminate infinite lists?
What would the EU’s position be with respect to a United Ireland?
What is the difference between increasing volume and increasing gain?
Can I return my ability to cast Wish by using Glyph of warding?
Found a minor bug, affecting 1% of users. What should QA do?
Anonymous reviewer disclosed his identity. Should I thank him by name?
Can an NPC use the teleport spell to affect an object they can see with the scry spell?
"cd" into /sys/kernel/debug/tracing causes permission change
Could Boris Johnson face criminal charges for illegally proroguing Parliament?
What is the origin of the minced oath “Jiminy”?
"Categorical" Schröder–Bernstein theorem?
In search of a pedagogically simple example of asymmetric encryption routine?
What does a textbook look like while you are writing it?
Sum of series with addition
Determine the Winner of a Game of Australian Football
How to catch creatures that can predict the next few minutes?
Is American Sign Language phonetic?
The answer is the same (tricky puzzle!)
Why is the time of useful consciousness only seconds at high altitudes?
Colleague's grant application resembles my PhD thesis
I've been fired, was allowed to announce it as if I quit and given extra notice, how to handle the questions?
Why do many websites hide input when entering a OTP
Did Joe Biden "stop a prosecution" into his son in Ukraine? And did he brag about stopping the prosecution?
How is the speed of nucleons in the nucleus measured?
How to "Start as close to the end as possible", and why to do so?
List comprehension guard equivalent of filterM
Haskell List Comprehensions guards in F#haskell - let/where equivalent within list comprehension?Haskell: Lists, Arrays, Vectors, SequencesFor a list comprehension in Haskell the equivalent in Scala?Using guards in list comprehensionsWhat are some better ways to write [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)] in Haskell?List comprehension guardsGetting my bearings on state-monadic “uncurrying”Combining elements with probabilities in HaskellGuards in list comprehensions don't terminate infinite lists?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
List comprehensions have overlapping functionality with map
and filter
. filterM
caters for the situation in which the predicate returns a Bool
wrapped in a monad (well, an Applicative, to be precise). mapM
does something similar for mapping functions whose result is wrapped in an Applicative.
In case you want to reproduce the behaviour of mapM
with a list comprehension, sequence
comes to the rescue. But how can filterM
be replaced with a list comprehension? In other words, how can a predicate which returns a Bool
inside a context, be used as a guard in list comprehensions?
Below are trivial examples exploring the 2x2x2 space (filter/map, function/comprehension, plain/monadic) of above observations, only I don't know how to write fcm
. How can fcm
be fixed so that it has the same value as ffm
?
import Control.Monad (filterM)
predicate = (>3)
convert = (*10)
predicateM = Just . predicate -- Just represents an arbitrary monad
convertM = Just . convert
data_ = [1..5]
ffp = filter predicate data_
ffm = filterM predicateM data_
fcp = [a | a <- data_, predicate a]
fcm = [a | a <- data_, predicateM a]
mfp = map convert data_
mfm = mapM convertM data_
mcp = [ convert a | a <- data_ ]
mcm = sequence [ convertM a | a <- data_ ]
Edit:
It's important to note that the versions whose name ends in m
must use a convertM
or predicateM
: the plain convert
and predicate
are unavailable in those situations; that's the whole point of the question.
Background information
The motivation arises from having a bunch of functions (here is a simplified collection, which is hopefully representative)
convert :: a -> r -> b
predicate :: a -> r -> Bool
big :: [a] -> r -> [b]
big as r = [ convert a r | a <- as, predicate a r ]
which are begging to be refactored in terms of Reader ... and one of which (big
) uses one of the others (predicate
) as a predicate in listcomp guard.
Refactoring works just fine, as long as the listcomp is replaced with a combination of mapM
and filterM
:
convertR :: a -> Reader r b
predicateR :: a -> Reader r Bool
bigR :: [a] -> Reader r [b]
bigR as = mapM convertR =<< filterM predicateR as
The trouble with this is that, in real life, the listcomp is much more complex, and the translation to mapM
and filterM
is far less clean.
Hence the motivation for wanting to keep the listcomp even when the predicate has turned monadic.
Edit 2
The real listcomp is more complex, because it combines elements from more than one list. I've tried to extact the essence of the problem into the following example, which differs from Edit 1 in that
- The listcomp in
big
takes data from more than one list. predicate
takes more than one value as input.convert
has been rename tocombine
and takes more than one value as input.- Similar changes for the
Reader
versions.
.
combine :: r -> (a,a) -> b
predicate :: r -> (a,a) -> Bool
big, big' :: r -> [a] -> [b]
big r as = [ combine r (a,b) | a <- as, b <- as, predicate r (a,b) ]
big' r as = map (combine r) $ filter (predicate r) $ [ (a,b) | a <- as, b <- as ]
combineR :: (a,a) -> Reader r b
predicateR :: (a,a) -> Reader r Bool
bigR, bigR' :: [a] -> Reader r [b]
bigR = undefined
bigR' as = mapM combineR =<< filterM predicateR =<< return [ (a,b) | a <- as, b <- as ]
big'
is a rewrite of big
in which combine
and predicate
are extracted from the listcomp. This has a direct equivalent in the Reader version: bigR'
. So, the question is, how can you write bigR
which should be
- Not significantly uglier than
bigR'
- As direct a translation of
big
as reasonably possible.
At this stage I'm tempted to conclude that bigR'
is as good as it's going to get. This implies that the answer to my question is:
- keep the listcomp for constructing the cartesian product
- move
predicate
andcombine
out of the expression into afilter
and amap
respectively - in the monadic version, replace
filter
andmap
withfilterM
andmapM
(and$
with=<<
). - uncurry the predicate and combiner functions: the listcomp works equally well with curried and uncurried versions, but the map-filter combination needs them to be curried. At this stage this is probably the biggest price to pay for losing the ability to use the listcomp.
haskell
|
show 2 more comments
List comprehensions have overlapping functionality with map
and filter
. filterM
caters for the situation in which the predicate returns a Bool
wrapped in a monad (well, an Applicative, to be precise). mapM
does something similar for mapping functions whose result is wrapped in an Applicative.
In case you want to reproduce the behaviour of mapM
with a list comprehension, sequence
comes to the rescue. But how can filterM
be replaced with a list comprehension? In other words, how can a predicate which returns a Bool
inside a context, be used as a guard in list comprehensions?
Below are trivial examples exploring the 2x2x2 space (filter/map, function/comprehension, plain/monadic) of above observations, only I don't know how to write fcm
. How can fcm
be fixed so that it has the same value as ffm
?
import Control.Monad (filterM)
predicate = (>3)
convert = (*10)
predicateM = Just . predicate -- Just represents an arbitrary monad
convertM = Just . convert
data_ = [1..5]
ffp = filter predicate data_
ffm = filterM predicateM data_
fcp = [a | a <- data_, predicate a]
fcm = [a | a <- data_, predicateM a]
mfp = map convert data_
mfm = mapM convertM data_
mcp = [ convert a | a <- data_ ]
mcm = sequence [ convertM a | a <- data_ ]
Edit:
It's important to note that the versions whose name ends in m
must use a convertM
or predicateM
: the plain convert
and predicate
are unavailable in those situations; that's the whole point of the question.
Background information
The motivation arises from having a bunch of functions (here is a simplified collection, which is hopefully representative)
convert :: a -> r -> b
predicate :: a -> r -> Bool
big :: [a] -> r -> [b]
big as r = [ convert a r | a <- as, predicate a r ]
which are begging to be refactored in terms of Reader ... and one of which (big
) uses one of the others (predicate
) as a predicate in listcomp guard.
Refactoring works just fine, as long as the listcomp is replaced with a combination of mapM
and filterM
:
convertR :: a -> Reader r b
predicateR :: a -> Reader r Bool
bigR :: [a] -> Reader r [b]
bigR as = mapM convertR =<< filterM predicateR as
The trouble with this is that, in real life, the listcomp is much more complex, and the translation to mapM
and filterM
is far less clean.
Hence the motivation for wanting to keep the listcomp even when the predicate has turned monadic.
Edit 2
The real listcomp is more complex, because it combines elements from more than one list. I've tried to extact the essence of the problem into the following example, which differs from Edit 1 in that
- The listcomp in
big
takes data from more than one list. predicate
takes more than one value as input.convert
has been rename tocombine
and takes more than one value as input.- Similar changes for the
Reader
versions.
.
combine :: r -> (a,a) -> b
predicate :: r -> (a,a) -> Bool
big, big' :: r -> [a] -> [b]
big r as = [ combine r (a,b) | a <- as, b <- as, predicate r (a,b) ]
big' r as = map (combine r) $ filter (predicate r) $ [ (a,b) | a <- as, b <- as ]
combineR :: (a,a) -> Reader r b
predicateR :: (a,a) -> Reader r Bool
bigR, bigR' :: [a] -> Reader r [b]
bigR = undefined
bigR' as = mapM combineR =<< filterM predicateR =<< return [ (a,b) | a <- as, b <- as ]
big'
is a rewrite of big
in which combine
and predicate
are extracted from the listcomp. This has a direct equivalent in the Reader version: bigR'
. So, the question is, how can you write bigR
which should be
- Not significantly uglier than
bigR'
- As direct a translation of
big
as reasonably possible.
At this stage I'm tempted to conclude that bigR'
is as good as it's going to get. This implies that the answer to my question is:
- keep the listcomp for constructing the cartesian product
- move
predicate
andcombine
out of the expression into afilter
and amap
respectively - in the monadic version, replace
filter
andmap
withfilterM
andmapM
(and$
with=<<
). - uncurry the predicate and combiner functions: the listcomp works equally well with curried and uncurried versions, but the map-filter combination needs them to be curried. At this stage this is probably the biggest price to pay for losing the ability to use the listcomp.
haskell
isn't it justfcm = Just [a | a <- data_, predicate a]
? (It can't result in aNothing
because(Just . predicate)
doesn't ever.)
– Robin Zigmond
Mar 28 at 16:07
@RobinZigmond Them
infcm
indicates that the predicate returnsm Bool
. By changing(Just . predicate)
topredicate
you've moved from thefcm
corner of the cube to thefcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)
– jacg
Mar 28 at 16:18
but a predicate by definition cannot returnm Bool
. It must return aBool
. You're thinking of the fact that the function argument tofilterM
is of typea -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim forfcm
was for it to produce the same result asffm
but using a list comp - what I've put above is the only way I see to do it.
– Robin Zigmond
Mar 28 at 16:21
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you havefcm :: [a] -> r -> [b]
andp :: a -> r -> Bool
.fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` andp :: a -> Reader r Bool
, which makesp
unusable in the listcomp. Changingxxx
froma -> r ->b
toa -> Reader r b
can be dealt with either by switching tomapM
or usingsequence
with the listcomp. I can see how to deal with the change inp
by replacing the listcomp withfilterM
, but can it be done without getting rid of the listcomp?
– jacg
Mar 28 at 16:38
@RobinZigmond Yes,fcm
is supposed to produce the same result asffm
using a listcomp ... while respecting the fact that the only function you had to supplyfilterM
has typea -> m Bool
.(Just . predicate)
represents the function I have to work with. I do not have the luxury of removing theJust .
– jacg
Mar 28 at 16:47
|
show 2 more comments
List comprehensions have overlapping functionality with map
and filter
. filterM
caters for the situation in which the predicate returns a Bool
wrapped in a monad (well, an Applicative, to be precise). mapM
does something similar for mapping functions whose result is wrapped in an Applicative.
In case you want to reproduce the behaviour of mapM
with a list comprehension, sequence
comes to the rescue. But how can filterM
be replaced with a list comprehension? In other words, how can a predicate which returns a Bool
inside a context, be used as a guard in list comprehensions?
Below are trivial examples exploring the 2x2x2 space (filter/map, function/comprehension, plain/monadic) of above observations, only I don't know how to write fcm
. How can fcm
be fixed so that it has the same value as ffm
?
import Control.Monad (filterM)
predicate = (>3)
convert = (*10)
predicateM = Just . predicate -- Just represents an arbitrary monad
convertM = Just . convert
data_ = [1..5]
ffp = filter predicate data_
ffm = filterM predicateM data_
fcp = [a | a <- data_, predicate a]
fcm = [a | a <- data_, predicateM a]
mfp = map convert data_
mfm = mapM convertM data_
mcp = [ convert a | a <- data_ ]
mcm = sequence [ convertM a | a <- data_ ]
Edit:
It's important to note that the versions whose name ends in m
must use a convertM
or predicateM
: the plain convert
and predicate
are unavailable in those situations; that's the whole point of the question.
Background information
The motivation arises from having a bunch of functions (here is a simplified collection, which is hopefully representative)
convert :: a -> r -> b
predicate :: a -> r -> Bool
big :: [a] -> r -> [b]
big as r = [ convert a r | a <- as, predicate a r ]
which are begging to be refactored in terms of Reader ... and one of which (big
) uses one of the others (predicate
) as a predicate in listcomp guard.
Refactoring works just fine, as long as the listcomp is replaced with a combination of mapM
and filterM
:
convertR :: a -> Reader r b
predicateR :: a -> Reader r Bool
bigR :: [a] -> Reader r [b]
bigR as = mapM convertR =<< filterM predicateR as
The trouble with this is that, in real life, the listcomp is much more complex, and the translation to mapM
and filterM
is far less clean.
Hence the motivation for wanting to keep the listcomp even when the predicate has turned monadic.
Edit 2
The real listcomp is more complex, because it combines elements from more than one list. I've tried to extact the essence of the problem into the following example, which differs from Edit 1 in that
- The listcomp in
big
takes data from more than one list. predicate
takes more than one value as input.convert
has been rename tocombine
and takes more than one value as input.- Similar changes for the
Reader
versions.
.
combine :: r -> (a,a) -> b
predicate :: r -> (a,a) -> Bool
big, big' :: r -> [a] -> [b]
big r as = [ combine r (a,b) | a <- as, b <- as, predicate r (a,b) ]
big' r as = map (combine r) $ filter (predicate r) $ [ (a,b) | a <- as, b <- as ]
combineR :: (a,a) -> Reader r b
predicateR :: (a,a) -> Reader r Bool
bigR, bigR' :: [a] -> Reader r [b]
bigR = undefined
bigR' as = mapM combineR =<< filterM predicateR =<< return [ (a,b) | a <- as, b <- as ]
big'
is a rewrite of big
in which combine
and predicate
are extracted from the listcomp. This has a direct equivalent in the Reader version: bigR'
. So, the question is, how can you write bigR
which should be
- Not significantly uglier than
bigR'
- As direct a translation of
big
as reasonably possible.
At this stage I'm tempted to conclude that bigR'
is as good as it's going to get. This implies that the answer to my question is:
- keep the listcomp for constructing the cartesian product
- move
predicate
andcombine
out of the expression into afilter
and amap
respectively - in the monadic version, replace
filter
andmap
withfilterM
andmapM
(and$
with=<<
). - uncurry the predicate and combiner functions: the listcomp works equally well with curried and uncurried versions, but the map-filter combination needs them to be curried. At this stage this is probably the biggest price to pay for losing the ability to use the listcomp.
haskell
List comprehensions have overlapping functionality with map
and filter
. filterM
caters for the situation in which the predicate returns a Bool
wrapped in a monad (well, an Applicative, to be precise). mapM
does something similar for mapping functions whose result is wrapped in an Applicative.
In case you want to reproduce the behaviour of mapM
with a list comprehension, sequence
comes to the rescue. But how can filterM
be replaced with a list comprehension? In other words, how can a predicate which returns a Bool
inside a context, be used as a guard in list comprehensions?
Below are trivial examples exploring the 2x2x2 space (filter/map, function/comprehension, plain/monadic) of above observations, only I don't know how to write fcm
. How can fcm
be fixed so that it has the same value as ffm
?
import Control.Monad (filterM)
predicate = (>3)
convert = (*10)
predicateM = Just . predicate -- Just represents an arbitrary monad
convertM = Just . convert
data_ = [1..5]
ffp = filter predicate data_
ffm = filterM predicateM data_
fcp = [a | a <- data_, predicate a]
fcm = [a | a <- data_, predicateM a]
mfp = map convert data_
mfm = mapM convertM data_
mcp = [ convert a | a <- data_ ]
mcm = sequence [ convertM a | a <- data_ ]
Edit:
It's important to note that the versions whose name ends in m
must use a convertM
or predicateM
: the plain convert
and predicate
are unavailable in those situations; that's the whole point of the question.
Background information
The motivation arises from having a bunch of functions (here is a simplified collection, which is hopefully representative)
convert :: a -> r -> b
predicate :: a -> r -> Bool
big :: [a] -> r -> [b]
big as r = [ convert a r | a <- as, predicate a r ]
which are begging to be refactored in terms of Reader ... and one of which (big
) uses one of the others (predicate
) as a predicate in listcomp guard.
Refactoring works just fine, as long as the listcomp is replaced with a combination of mapM
and filterM
:
convertR :: a -> Reader r b
predicateR :: a -> Reader r Bool
bigR :: [a] -> Reader r [b]
bigR as = mapM convertR =<< filterM predicateR as
The trouble with this is that, in real life, the listcomp is much more complex, and the translation to mapM
and filterM
is far less clean.
Hence the motivation for wanting to keep the listcomp even when the predicate has turned monadic.
Edit 2
The real listcomp is more complex, because it combines elements from more than one list. I've tried to extact the essence of the problem into the following example, which differs from Edit 1 in that
- The listcomp in
big
takes data from more than one list. predicate
takes more than one value as input.convert
has been rename tocombine
and takes more than one value as input.- Similar changes for the
Reader
versions.
.
combine :: r -> (a,a) -> b
predicate :: r -> (a,a) -> Bool
big, big' :: r -> [a] -> [b]
big r as = [ combine r (a,b) | a <- as, b <- as, predicate r (a,b) ]
big' r as = map (combine r) $ filter (predicate r) $ [ (a,b) | a <- as, b <- as ]
combineR :: (a,a) -> Reader r b
predicateR :: (a,a) -> Reader r Bool
bigR, bigR' :: [a] -> Reader r [b]
bigR = undefined
bigR' as = mapM combineR =<< filterM predicateR =<< return [ (a,b) | a <- as, b <- as ]
big'
is a rewrite of big
in which combine
and predicate
are extracted from the listcomp. This has a direct equivalent in the Reader version: bigR'
. So, the question is, how can you write bigR
which should be
- Not significantly uglier than
bigR'
- As direct a translation of
big
as reasonably possible.
At this stage I'm tempted to conclude that bigR'
is as good as it's going to get. This implies that the answer to my question is:
- keep the listcomp for constructing the cartesian product
- move
predicate
andcombine
out of the expression into afilter
and amap
respectively - in the monadic version, replace
filter
andmap
withfilterM
andmapM
(and$
with=<<
). - uncurry the predicate and combiner functions: the listcomp works equally well with curried and uncurried versions, but the map-filter combination needs them to be curried. At this stage this is probably the biggest price to pay for losing the ability to use the listcomp.
haskell
haskell
edited Mar 29 at 12:45
jacg
asked Mar 28 at 15:52
jacgjacg
1,2086 silver badges19 bronze badges
1,2086 silver badges19 bronze badges
isn't it justfcm = Just [a | a <- data_, predicate a]
? (It can't result in aNothing
because(Just . predicate)
doesn't ever.)
– Robin Zigmond
Mar 28 at 16:07
@RobinZigmond Them
infcm
indicates that the predicate returnsm Bool
. By changing(Just . predicate)
topredicate
you've moved from thefcm
corner of the cube to thefcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)
– jacg
Mar 28 at 16:18
but a predicate by definition cannot returnm Bool
. It must return aBool
. You're thinking of the fact that the function argument tofilterM
is of typea -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim forfcm
was for it to produce the same result asffm
but using a list comp - what I've put above is the only way I see to do it.
– Robin Zigmond
Mar 28 at 16:21
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you havefcm :: [a] -> r -> [b]
andp :: a -> r -> Bool
.fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` andp :: a -> Reader r Bool
, which makesp
unusable in the listcomp. Changingxxx
froma -> r ->b
toa -> Reader r b
can be dealt with either by switching tomapM
or usingsequence
with the listcomp. I can see how to deal with the change inp
by replacing the listcomp withfilterM
, but can it be done without getting rid of the listcomp?
– jacg
Mar 28 at 16:38
@RobinZigmond Yes,fcm
is supposed to produce the same result asffm
using a listcomp ... while respecting the fact that the only function you had to supplyfilterM
has typea -> m Bool
.(Just . predicate)
represents the function I have to work with. I do not have the luxury of removing theJust .
– jacg
Mar 28 at 16:47
|
show 2 more comments
isn't it justfcm = Just [a | a <- data_, predicate a]
? (It can't result in aNothing
because(Just . predicate)
doesn't ever.)
– Robin Zigmond
Mar 28 at 16:07
@RobinZigmond Them
infcm
indicates that the predicate returnsm Bool
. By changing(Just . predicate)
topredicate
you've moved from thefcm
corner of the cube to thefcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)
– jacg
Mar 28 at 16:18
but a predicate by definition cannot returnm Bool
. It must return aBool
. You're thinking of the fact that the function argument tofilterM
is of typea -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim forfcm
was for it to produce the same result asffm
but using a list comp - what I've put above is the only way I see to do it.
– Robin Zigmond
Mar 28 at 16:21
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you havefcm :: [a] -> r -> [b]
andp :: a -> r -> Bool
.fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` andp :: a -> Reader r Bool
, which makesp
unusable in the listcomp. Changingxxx
froma -> r ->b
toa -> Reader r b
can be dealt with either by switching tomapM
or usingsequence
with the listcomp. I can see how to deal with the change inp
by replacing the listcomp withfilterM
, but can it be done without getting rid of the listcomp?
– jacg
Mar 28 at 16:38
@RobinZigmond Yes,fcm
is supposed to produce the same result asffm
using a listcomp ... while respecting the fact that the only function you had to supplyfilterM
has typea -> m Bool
.(Just . predicate)
represents the function I have to work with. I do not have the luxury of removing theJust .
– jacg
Mar 28 at 16:47
isn't it just
fcm = Just [a | a <- data_, predicate a]
? (It can't result in a Nothing
because (Just . predicate)
doesn't ever.)– Robin Zigmond
Mar 28 at 16:07
isn't it just
fcm = Just [a | a <- data_, predicate a]
? (It can't result in a Nothing
because (Just . predicate)
doesn't ever.)– Robin Zigmond
Mar 28 at 16:07
@RobinZigmond The
m
in fcm
indicates that the predicate returns m Bool
. By changing (Just . predicate)
to predicate
you've moved from the fcm
corner of the cube to the fcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)– jacg
Mar 28 at 16:18
@RobinZigmond The
m
in fcm
indicates that the predicate returns m Bool
. By changing (Just . predicate)
to predicate
you've moved from the fcm
corner of the cube to the fcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)– jacg
Mar 28 at 16:18
but a predicate by definition cannot return
m Bool
. It must return a Bool
. You're thinking of the fact that the function argument to filterM
is of type a -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim for fcm
was for it to produce the same result as ffm
but using a list comp - what I've put above is the only way I see to do it.– Robin Zigmond
Mar 28 at 16:21
but a predicate by definition cannot return
m Bool
. It must return a Bool
. You're thinking of the fact that the function argument to filterM
is of type a -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim for fcm
was for it to produce the same result as ffm
but using a list comp - what I've put above is the only way I see to do it.– Robin Zigmond
Mar 28 at 16:21
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you have
fcm :: [a] -> r -> [b]
and p :: a -> r -> Bool
. fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` and p :: a -> Reader r Bool
, which makes p
unusable in the listcomp. Changing xxx
from a -> r ->b
to a -> Reader r b
can be dealt with either by switching to mapM
or using sequence
with the listcomp. I can see how to deal with the change in p
by replacing the listcomp with filterM
, but can it be done without getting rid of the listcomp?– jacg
Mar 28 at 16:38
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you have
fcm :: [a] -> r -> [b]
and p :: a -> r -> Bool
. fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` and p :: a -> Reader r Bool
, which makes p
unusable in the listcomp. Changing xxx
from a -> r ->b
to a -> Reader r b
can be dealt with either by switching to mapM
or using sequence
with the listcomp. I can see how to deal with the change in p
by replacing the listcomp with filterM
, but can it be done without getting rid of the listcomp?– jacg
Mar 28 at 16:38
@RobinZigmond Yes,
fcm
is supposed to produce the same result as ffm
using a listcomp ... while respecting the fact that the only function you had to supply filterM
has type a -> m Bool
. (Just . predicate)
represents the function I have to work with. I do not have the luxury of removing the Just .
– jacg
Mar 28 at 16:47
@RobinZigmond Yes,
fcm
is supposed to produce the same result as ffm
using a listcomp ... while respecting the fact that the only function you had to supply filterM
has type a -> m Bool
. (Just . predicate)
represents the function I have to work with. I do not have the luxury of removing the Just .
– jacg
Mar 28 at 16:47
|
show 2 more comments
2 Answers
2
active
oldest
votes
Personally, I can't figure out a way to do it with just a list comp, but this might get you closer? (I've listed some intermediate steps I went through so you can take it in a different direction if you need).
-# LANGUAGE MonadComprehensions #-
predicateM = return . (>3)
[[a | True <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num b, Ord b, Control.Monad.Fail.MonadFail m) => [m b]
[[if b then Just a else Nothing | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
[[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
catMaybes <$> sequence [[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Monad f, Num a, Ord a) => f [a]
filterM' p xs = catMaybes <$> sequence [[bool Nothing (Just a) b | b <- p a] | a <- xs]
There may be something neater with a ListT
?
EDIT: Another approach, although it spews some warnings about ListT
giving unlawful instances..
unListT (ListT x) = x
filterM'' p xs = unListT [a | (a,True) <- ListT $ mapM (x -> return . (x,) =<< p x) xs]
EDIT2: Okay I got it down to a single comprehension!
filterM''' :: (Traversable m1, Monad m2, Monad m1, Alternative m1) => (b -> m2 Bool) -> m1 b -> m2 (m1 b)
filterM''' p xs = [[a | (a,b) <- mlist, b] | mlist <- mapM (x -> return . (x,) =<< p x) xs]
EDIT3: Another approach, because I'm not sure on precisely what you need access to.
filterM' p xs = [x | x <- filterM p xs]
Then, nest the comprehensions to obtain access to the "inner" element type eg. filtering and mapping,
filterMap f p xs = [[f x | x <- mlist] | mlist <- filterM p xs]
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-filterM
-mapM
approach?
– jacg
Mar 29 at 12:05
add a comment
|
import Control.Monad.Trans.Reader
import Control.Monad (filterM)
The question was motivated by the desire to take some functions of the form
f :: x -> y -> z -> a ; f = undefined
p :: x -> y -> z -> Bool ; p = undefined
u :: [x] -> [y] -> [z] -> [a]
and replace them with similar ones within some context (Reader
in this example):
fR :: x -> y -> z -> Reader r a ; fR = undefined
pR :: x -> y -> z -> Reader r Bool ; pR = undefined
uR :: [x] -> [y] -> [z] -> Reader r [a]
At the core of the question, one of the original functions has a multi-input list comprehension that uses the other functions for combining and filtering purposes:
u xs ys zs = [ f x y z | x <- xs, y <- ys, z <- zs, p x y z ]
The question addresses the difficulties of implementing the equivalent, contextful, uR
function; specifically the apparent loss of ability to use a list comprehension and its conveniences.
There is a fairly neat translation of u
into an implementation that combines a list comprehension, filter
and map
. This is shown as u'
below. u'
has a direct translation to the contextful version, uR
:
u' xs ys zs = map ucf $ filter ucp $ cartesian xs ys zs
uR xs ys zs = mapM ucfR =<< filterM ucpR =<< return (cartesian xs ys zs)
In the above, the list comprehension is packed up in cartesian
cartesian xs ys zs = [ (x,y,z) | x <- xs, y <- ys, z <- zs ]
and the solution requires the original functions (p
, f
, pR
and fR
) to be uncurried:
ucp = uncurry3 p ; ucpR = uncurry3 pR
ucf = uncurry3 f ; ucfR = uncurry3 fR
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f = (a,b,c) -> f a b c
Maybe this solution can be sugared with a monad comprehension, but I haven't the time to think about that right now.
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!
– moonGoose
Mar 29 at 21:04
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55401900%2flist-comprehension-guard-equivalent-of-filterm%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Personally, I can't figure out a way to do it with just a list comp, but this might get you closer? (I've listed some intermediate steps I went through so you can take it in a different direction if you need).
-# LANGUAGE MonadComprehensions #-
predicateM = return . (>3)
[[a | True <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num b, Ord b, Control.Monad.Fail.MonadFail m) => [m b]
[[if b then Just a else Nothing | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
[[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
catMaybes <$> sequence [[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Monad f, Num a, Ord a) => f [a]
filterM' p xs = catMaybes <$> sequence [[bool Nothing (Just a) b | b <- p a] | a <- xs]
There may be something neater with a ListT
?
EDIT: Another approach, although it spews some warnings about ListT
giving unlawful instances..
unListT (ListT x) = x
filterM'' p xs = unListT [a | (a,True) <- ListT $ mapM (x -> return . (x,) =<< p x) xs]
EDIT2: Okay I got it down to a single comprehension!
filterM''' :: (Traversable m1, Monad m2, Monad m1, Alternative m1) => (b -> m2 Bool) -> m1 b -> m2 (m1 b)
filterM''' p xs = [[a | (a,b) <- mlist, b] | mlist <- mapM (x -> return . (x,) =<< p x) xs]
EDIT3: Another approach, because I'm not sure on precisely what you need access to.
filterM' p xs = [x | x <- filterM p xs]
Then, nest the comprehensions to obtain access to the "inner" element type eg. filtering and mapping,
filterMap f p xs = [[f x | x <- mlist] | mlist <- filterM p xs]
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-filterM
-mapM
approach?
– jacg
Mar 29 at 12:05
add a comment
|
Personally, I can't figure out a way to do it with just a list comp, but this might get you closer? (I've listed some intermediate steps I went through so you can take it in a different direction if you need).
-# LANGUAGE MonadComprehensions #-
predicateM = return . (>3)
[[a | True <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num b, Ord b, Control.Monad.Fail.MonadFail m) => [m b]
[[if b then Just a else Nothing | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
[[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
catMaybes <$> sequence [[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Monad f, Num a, Ord a) => f [a]
filterM' p xs = catMaybes <$> sequence [[bool Nothing (Just a) b | b <- p a] | a <- xs]
There may be something neater with a ListT
?
EDIT: Another approach, although it spews some warnings about ListT
giving unlawful instances..
unListT (ListT x) = x
filterM'' p xs = unListT [a | (a,True) <- ListT $ mapM (x -> return . (x,) =<< p x) xs]
EDIT2: Okay I got it down to a single comprehension!
filterM''' :: (Traversable m1, Monad m2, Monad m1, Alternative m1) => (b -> m2 Bool) -> m1 b -> m2 (m1 b)
filterM''' p xs = [[a | (a,b) <- mlist, b] | mlist <- mapM (x -> return . (x,) =<< p x) xs]
EDIT3: Another approach, because I'm not sure on precisely what you need access to.
filterM' p xs = [x | x <- filterM p xs]
Then, nest the comprehensions to obtain access to the "inner" element type eg. filtering and mapping,
filterMap f p xs = [[f x | x <- mlist] | mlist <- filterM p xs]
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-filterM
-mapM
approach?
– jacg
Mar 29 at 12:05
add a comment
|
Personally, I can't figure out a way to do it with just a list comp, but this might get you closer? (I've listed some intermediate steps I went through so you can take it in a different direction if you need).
-# LANGUAGE MonadComprehensions #-
predicateM = return . (>3)
[[a | True <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num b, Ord b, Control.Monad.Fail.MonadFail m) => [m b]
[[if b then Just a else Nothing | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
[[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
catMaybes <$> sequence [[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Monad f, Num a, Ord a) => f [a]
filterM' p xs = catMaybes <$> sequence [[bool Nothing (Just a) b | b <- p a] | a <- xs]
There may be something neater with a ListT
?
EDIT: Another approach, although it spews some warnings about ListT
giving unlawful instances..
unListT (ListT x) = x
filterM'' p xs = unListT [a | (a,True) <- ListT $ mapM (x -> return . (x,) =<< p x) xs]
EDIT2: Okay I got it down to a single comprehension!
filterM''' :: (Traversable m1, Monad m2, Monad m1, Alternative m1) => (b -> m2 Bool) -> m1 b -> m2 (m1 b)
filterM''' p xs = [[a | (a,b) <- mlist, b] | mlist <- mapM (x -> return . (x,) =<< p x) xs]
EDIT3: Another approach, because I'm not sure on precisely what you need access to.
filterM' p xs = [x | x <- filterM p xs]
Then, nest the comprehensions to obtain access to the "inner" element type eg. filtering and mapping,
filterMap f p xs = [[f x | x <- mlist] | mlist <- filterM p xs]
Personally, I can't figure out a way to do it with just a list comp, but this might get you closer? (I've listed some intermediate steps I went through so you can take it in a different direction if you need).
-# LANGUAGE MonadComprehensions #-
predicateM = return . (>3)
[[a | True <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num b, Ord b, Control.Monad.Fail.MonadFail m) => [m b]
[[if b then Just a else Nothing | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
[[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Num a, Monad m, Ord a) => [m (Maybe a)]
catMaybes <$> sequence [[bool Nothing (Just a) b | b <- predicateM a] | a <- [1,2,3,4,5]]
:: (Monad f, Num a, Ord a) => f [a]
filterM' p xs = catMaybes <$> sequence [[bool Nothing (Just a) b | b <- p a] | a <- xs]
There may be something neater with a ListT
?
EDIT: Another approach, although it spews some warnings about ListT
giving unlawful instances..
unListT (ListT x) = x
filterM'' p xs = unListT [a | (a,True) <- ListT $ mapM (x -> return . (x,) =<< p x) xs]
EDIT2: Okay I got it down to a single comprehension!
filterM''' :: (Traversable m1, Monad m2, Monad m1, Alternative m1) => (b -> m2 Bool) -> m1 b -> m2 (m1 b)
filterM''' p xs = [[a | (a,b) <- mlist, b] | mlist <- mapM (x -> return . (x,) =<< p x) xs]
EDIT3: Another approach, because I'm not sure on precisely what you need access to.
filterM' p xs = [x | x <- filterM p xs]
Then, nest the comprehensions to obtain access to the "inner" element type eg. filtering and mapping,
filterMap f p xs = [[f x | x <- mlist] | mlist <- filterM p xs]
edited Mar 29 at 0:16
answered Mar 28 at 21:12
moonGoosemoonGoose
1,2532 silver badges12 bronze badges
1,2532 silver badges12 bronze badges
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-filterM
-mapM
approach?
– jacg
Mar 29 at 12:05
add a comment
|
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-filterM
-mapM
approach?
– jacg
Mar 29 at 12:05
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-
filterM
-mapM
approach?– jacg
Mar 29 at 12:05
I've added another edit, to emphasize the pragmatic motivation behind this. The point isn't to force it into a listcomp for the hell of it (fun and interesting though that may be!) In my edit you can see that the listcomp uses multiple input sets, and that there is a very clean translation to map+filter, which has a very clean translation to the monadic version, but it comes at the cost of having to uncurry the predicate and combiner. So the big-picture question is: is there a way of wirting it as a listcomp that is neater than the uncurry-
filterM
-mapM
approach?– jacg
Mar 29 at 12:05
add a comment
|
import Control.Monad.Trans.Reader
import Control.Monad (filterM)
The question was motivated by the desire to take some functions of the form
f :: x -> y -> z -> a ; f = undefined
p :: x -> y -> z -> Bool ; p = undefined
u :: [x] -> [y] -> [z] -> [a]
and replace them with similar ones within some context (Reader
in this example):
fR :: x -> y -> z -> Reader r a ; fR = undefined
pR :: x -> y -> z -> Reader r Bool ; pR = undefined
uR :: [x] -> [y] -> [z] -> Reader r [a]
At the core of the question, one of the original functions has a multi-input list comprehension that uses the other functions for combining and filtering purposes:
u xs ys zs = [ f x y z | x <- xs, y <- ys, z <- zs, p x y z ]
The question addresses the difficulties of implementing the equivalent, contextful, uR
function; specifically the apparent loss of ability to use a list comprehension and its conveniences.
There is a fairly neat translation of u
into an implementation that combines a list comprehension, filter
and map
. This is shown as u'
below. u'
has a direct translation to the contextful version, uR
:
u' xs ys zs = map ucf $ filter ucp $ cartesian xs ys zs
uR xs ys zs = mapM ucfR =<< filterM ucpR =<< return (cartesian xs ys zs)
In the above, the list comprehension is packed up in cartesian
cartesian xs ys zs = [ (x,y,z) | x <- xs, y <- ys, z <- zs ]
and the solution requires the original functions (p
, f
, pR
and fR
) to be uncurried:
ucp = uncurry3 p ; ucpR = uncurry3 pR
ucf = uncurry3 f ; ucfR = uncurry3 fR
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f = (a,b,c) -> f a b c
Maybe this solution can be sugared with a monad comprehension, but I haven't the time to think about that right now.
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!
– moonGoose
Mar 29 at 21:04
add a comment
|
import Control.Monad.Trans.Reader
import Control.Monad (filterM)
The question was motivated by the desire to take some functions of the form
f :: x -> y -> z -> a ; f = undefined
p :: x -> y -> z -> Bool ; p = undefined
u :: [x] -> [y] -> [z] -> [a]
and replace them with similar ones within some context (Reader
in this example):
fR :: x -> y -> z -> Reader r a ; fR = undefined
pR :: x -> y -> z -> Reader r Bool ; pR = undefined
uR :: [x] -> [y] -> [z] -> Reader r [a]
At the core of the question, one of the original functions has a multi-input list comprehension that uses the other functions for combining and filtering purposes:
u xs ys zs = [ f x y z | x <- xs, y <- ys, z <- zs, p x y z ]
The question addresses the difficulties of implementing the equivalent, contextful, uR
function; specifically the apparent loss of ability to use a list comprehension and its conveniences.
There is a fairly neat translation of u
into an implementation that combines a list comprehension, filter
and map
. This is shown as u'
below. u'
has a direct translation to the contextful version, uR
:
u' xs ys zs = map ucf $ filter ucp $ cartesian xs ys zs
uR xs ys zs = mapM ucfR =<< filterM ucpR =<< return (cartesian xs ys zs)
In the above, the list comprehension is packed up in cartesian
cartesian xs ys zs = [ (x,y,z) | x <- xs, y <- ys, z <- zs ]
and the solution requires the original functions (p
, f
, pR
and fR
) to be uncurried:
ucp = uncurry3 p ; ucpR = uncurry3 pR
ucf = uncurry3 f ; ucfR = uncurry3 fR
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f = (a,b,c) -> f a b c
Maybe this solution can be sugared with a monad comprehension, but I haven't the time to think about that right now.
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!
– moonGoose
Mar 29 at 21:04
add a comment
|
import Control.Monad.Trans.Reader
import Control.Monad (filterM)
The question was motivated by the desire to take some functions of the form
f :: x -> y -> z -> a ; f = undefined
p :: x -> y -> z -> Bool ; p = undefined
u :: [x] -> [y] -> [z] -> [a]
and replace them with similar ones within some context (Reader
in this example):
fR :: x -> y -> z -> Reader r a ; fR = undefined
pR :: x -> y -> z -> Reader r Bool ; pR = undefined
uR :: [x] -> [y] -> [z] -> Reader r [a]
At the core of the question, one of the original functions has a multi-input list comprehension that uses the other functions for combining and filtering purposes:
u xs ys zs = [ f x y z | x <- xs, y <- ys, z <- zs, p x y z ]
The question addresses the difficulties of implementing the equivalent, contextful, uR
function; specifically the apparent loss of ability to use a list comprehension and its conveniences.
There is a fairly neat translation of u
into an implementation that combines a list comprehension, filter
and map
. This is shown as u'
below. u'
has a direct translation to the contextful version, uR
:
u' xs ys zs = map ucf $ filter ucp $ cartesian xs ys zs
uR xs ys zs = mapM ucfR =<< filterM ucpR =<< return (cartesian xs ys zs)
In the above, the list comprehension is packed up in cartesian
cartesian xs ys zs = [ (x,y,z) | x <- xs, y <- ys, z <- zs ]
and the solution requires the original functions (p
, f
, pR
and fR
) to be uncurried:
ucp = uncurry3 p ; ucpR = uncurry3 pR
ucf = uncurry3 f ; ucfR = uncurry3 fR
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f = (a,b,c) -> f a b c
Maybe this solution can be sugared with a monad comprehension, but I haven't the time to think about that right now.
import Control.Monad.Trans.Reader
import Control.Monad (filterM)
The question was motivated by the desire to take some functions of the form
f :: x -> y -> z -> a ; f = undefined
p :: x -> y -> z -> Bool ; p = undefined
u :: [x] -> [y] -> [z] -> [a]
and replace them with similar ones within some context (Reader
in this example):
fR :: x -> y -> z -> Reader r a ; fR = undefined
pR :: x -> y -> z -> Reader r Bool ; pR = undefined
uR :: [x] -> [y] -> [z] -> Reader r [a]
At the core of the question, one of the original functions has a multi-input list comprehension that uses the other functions for combining and filtering purposes:
u xs ys zs = [ f x y z | x <- xs, y <- ys, z <- zs, p x y z ]
The question addresses the difficulties of implementing the equivalent, contextful, uR
function; specifically the apparent loss of ability to use a list comprehension and its conveniences.
There is a fairly neat translation of u
into an implementation that combines a list comprehension, filter
and map
. This is shown as u'
below. u'
has a direct translation to the contextful version, uR
:
u' xs ys zs = map ucf $ filter ucp $ cartesian xs ys zs
uR xs ys zs = mapM ucfR =<< filterM ucpR =<< return (cartesian xs ys zs)
In the above, the list comprehension is packed up in cartesian
cartesian xs ys zs = [ (x,y,z) | x <- xs, y <- ys, z <- zs ]
and the solution requires the original functions (p
, f
, pR
and fR
) to be uncurried:
ucp = uncurry3 p ; ucpR = uncurry3 pR
ucf = uncurry3 f ; ucfR = uncurry3 fR
uncurry3 :: (a -> b -> c -> r) -> (a, b, c) -> r
uncurry3 f = (a,b,c) -> f a b c
Maybe this solution can be sugared with a monad comprehension, but I haven't the time to think about that right now.
answered Mar 29 at 12:38
jacgjacg
1,2086 silver badges19 bronze badges
1,2086 silver badges19 bronze badges
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!
– moonGoose
Mar 29 at 21:04
add a comment
|
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!
– moonGoose
Mar 29 at 21:04
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,
uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!– moonGoose
Mar 29 at 21:04
Sorry, the reason I wrote a few different versions was because I was experimenting myself and also because I wasn't exactly sure on your requirements. You have a few options,
uR xs ys zs = sequence [ join [ fR x y z | True <- pR x y z ] | x <- xs, y <- ys, z <- zs ]
is one of the clearer. You could remove the join by complicating the inner comprehension, and/or you can change the MonadFail constraint to Alternative by matching on the Bool directly ..[ r | r <- fR x y z, p <- pR x y z, p]
(here both changes demonstrated). You may still feel the non-comprehension versions clearer though!– moonGoose
Mar 29 at 21:04
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55401900%2flist-comprehension-guard-equivalent-of-filterm%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
isn't it just
fcm = Just [a | a <- data_, predicate a]
? (It can't result in aNothing
because(Just . predicate)
doesn't ever.)– Robin Zigmond
Mar 28 at 16:07
@RobinZigmond The
m
infcm
indicates that the predicate returnsm Bool
. By changing(Just . predicate)
topredicate
you've moved from thefcm
corner of the cube to thefcp
corner. The whole point is that, for whatever reason, the predicate returns a monad, and I don't have the option of changing that, I just have to deal with it. (In real life this came up when refactoring a bunch of functions into the Reader monad, and suddenly my predicate turned monadic and my lisctomp broke.)– jacg
Mar 28 at 16:18
but a predicate by definition cannot return
m Bool
. It must return aBool
. You're thinking of the fact that the function argument tofilterM
is of typea -> m Bool
, but you can't use that in a list comprehension because it's not actually a predicate. I thought the aim forfcm
was for it to produce the same result asffm
but using a list comp - what I've put above is the only way I see to do it.– Robin Zigmond
Mar 28 at 16:21
@RobinZigmond As I said, this is motivated by refactoring to Reader. Imagine you have
fcm :: [a] -> r -> [b]
andp :: a -> r -> Bool
.fcm a r = [ xxx a r | a <- as , p a r]. Then you try to refactor to
fcm :: [a] -> Reader r [b]` andp :: a -> Reader r Bool
, which makesp
unusable in the listcomp. Changingxxx
froma -> r ->b
toa -> Reader r b
can be dealt with either by switching tomapM
or usingsequence
with the listcomp. I can see how to deal with the change inp
by replacing the listcomp withfilterM
, but can it be done without getting rid of the listcomp?– jacg
Mar 28 at 16:38
@RobinZigmond Yes,
fcm
is supposed to produce the same result asffm
using a listcomp ... while respecting the fact that the only function you had to supplyfilterM
has typea -> m Bool
.(Just . predicate)
represents the function I have to work with. I do not have the luxury of removing theJust .
– jacg
Mar 28 at 16:47