考虑一下:
map fromEnum $ zipWith (==) "aaaa" "abaa"
-- [1,0,1,1]
在这里只有一步是很好的:
zipWith (\x y -> fromEnum (x == y)) "aaaa" "abaa"
现在我可以取消y
:
zipWith (\x -> fromEnum.(x ==)) "aaaa" "abaa"
但我没有消除x
。当然有办法“欺骗”......
zipWith (curry (fromEnum . uncurry (==))) "aaaa" "abaa"
......但这看起来比原来的lambda更丑。
我寻找的功能与Data.Function.on
有些相似,但“相反”。我觉得有一个令人尴尬的简单解决方案。我忽视了什么吗?
答案 0 :(得分:7)
zipWith (\x -> fromEnum . (x ==)) "aaaa" "abaa"
可以写成
zipWith (\x -> (fromEnum .) (x ==)) "aaaa" "abaa"
可以写成
zipWith ((fromEnum .) . (==)) "aaaa" "abaa"
如果您发现这种可读性取决于我的口味。
编辑:另一个很好的方法是使用some combinators by Matt Hellige:
zipWith ((==) $. id ~> id ~> fromEnum) "aaaa" "abaa"
答案 1 :(得分:3)
没有预定义的库函数可以完成您想要的这种函数组合。但是如果你经常使用像问题中那样的结构,你可以定义这样一个函数:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
g .: f = \x y -> g (f x y)
x = zipWith (fromEnum .: (==)) "aaaa" "abaa"
答案 2 :(得分:1)
我已经定义了以下两个组合器用于美化(.)
的部分:
(|.>)
:您可以阅读以下定义:右侧切片f
,并使用g
撰写。
(|.>) :: (b -> c) -> (a -> a' -> b) -> (a -> a' -> c)
f |.> g = (f .) . g
(<.|)
:您可以阅读以下定义:左侧切片g
,并使用f
撰写。
(<.|) :: (a -> b -> c) -> (a' -> b) -> (a -> a' -> c)
f <.| g = (. g) . f
箭头方向表示组成发生的方向。在这两个组合器中,第一个可以在您的示例中使用,如下所示:
zipWith (fromEnum |.> (==)) "aaaa" "abaa"