Consider this:
map fromEnum $ zipWith (==) "aaaa" "abaa"
-- [1,0,1,1]
It would be nice to have only one step here:
zipWith (\x y -> fro开发者_运维百科mEnum (x == y)) "aaaa" "abaa"
Now I can eliminate y
:
zipWith (\x -> fromEnum.(x ==)) "aaaa" "abaa"
But I fail to eliminate x
. Of course there are ways to "cheat"...
zipWith (curry (fromEnum . uncurry (==))) "aaaa" "abaa"
... but this looks uglier than the original lambda.
The function I look for would be somewhat similar to Data.Function.on
, but "the other way around". I have the feeling that there is an embarrassingly simple solution for this. Do I overlook something?
zipWith (\x -> fromEnum . (x ==)) "aaaa" "abaa"
can be written as
zipWith (\x -> (fromEnum .) (x ==)) "aaaa" "abaa"
which can be written as
zipWith ((fromEnum .) . (==)) "aaaa" "abaa"
If you find this readable depends on taste I guess.
EDIT: Another nice way to do it is with some combinators by Matt Hellige:
zipWith ((==) $. id ~> id ~> fromEnum) "aaaa" "abaa"
There are no predefined library functions that do exactly this kind of function composition you want here. But if you are often using constructs like the one in the question, you could define such a function:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
g .: f = \x y -> g (f x y)
x = zipWith (fromEnum .: (==)) "aaaa" "abaa"
I have defined following two combinators for prettifying sections of (.)
:
(|.>)
: You can read the following definition as, slicef
on right and compose withg
.(|.>) :: (b -> c) -> (a -> a' -> b) -> (a -> a' -> c) f |.> g = (f .) . g
(<.|)
: You can read the following definition as, sliceg
on left and compose withf
.(<.|) :: (a -> b -> c) -> (a' -> b) -> (a -> a' -> c) f <.| g = (. g) . f
The direction of arrow indicates the direction in which composition is taking place. Of these two combinators, the first one can be used in your example as follows:
zipWith (fromEnum |.> (==)) "aaaa" "abaa"
精彩评论