与二元算子的组合?

时间:2011-07-06 15:36:39

标签: haskell function-composition

我想做一些相当简单的事情; 我使用运算符(++)与Data.Map insertWith ,它工作正常,但我想消除创建的值中的重复,所以想要用小块组成它。

我试过(nub(++)),(nub $(++)),(nub。(++)),一切都无济于事,因为(++)的类型与预期的不匹配小块的类型([a])。

我当然可以定义一个辅助函数或一个lambda,但我认为可能会有一个更清晰的组合。

请提示!

5 个答案:

答案 0 :(得分:10)

您可以将其写为

((nub .) .) (++)

示例:

Prelude Data.List> ((nub .) .) (++) [1,2,3] [3,4,5]
[1,2,3,4,5]

一般来说,你有

(f . ) g x = f (g x) 
((f . ) . ) g x y = f (g x y) 
(((f . ) . ) . ) g x y z = f (g x y z) 
((((f . ) . ) . ) . ) g x y z v = f (g x y z v)
...

以下是((nub .) .)

的此身份的推导
(f . g) x = f (g x)

(nub .) :: Eq a1 => (a -> [a1]) -> a -> [a1] 
(nub .) = \g x -> (nub (g x))

((nub .) .) :: Eq a2 => (a -> a1 -> [a2]) -> a -> a1 -> [a2]
((nub .) .) = ((\g x -> (nub (g x))) .) = (\g' x' -> (\g x -> (nub (g x))) (g' x'))
            = \g' x' x -> (nub ((g' x') x))

关于这个(和相关的)习语有一个nice article,但是用俄语: - (

答案 1 :(得分:6)

你想要的似乎是二元和一元函数的组合,如下所示:

compose :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
compose unary binary a b = unary (binary a b)

您要求提供无点版本(不提及ab变量)。让我们一个接一个地尝试消除它们。我们将从b开始,使用f (g x) = f . g

这一事实
compose unary binary a = unary . binary a
接下来是

a。让我们首先考虑表达式:

compose unary binary a = ((.) unary) (binary a)

再次应用相同的构图规则:

compose unary binary = ((.) unary) . binary

这可以写成:

compose unary = (.) ((.) unary)

甚至是

compose = (.) . (.)

这里,每个(.)'剥离'二进制函数的参数,你需要其中两个,因为函数是二进制的。当对任何仿函数进行推广时,这个习惯用法非常有用:fmap . fmap(注意,当函数被视为函子时,fmap等同于.)。这允许你“剥离”任何仿函数,例如你可以写:

incrementResultsOfEveryFunctionInTwoDimentionalList :: [[String -> Integer]] -> [[String -> Integer]]
incrementResultsOfEveryFunctionInTwoDimentionalList = fmap . fmap . fmap $ (+1)

所以,你的结果变成了:

(fmap . fmap) nub (++)

编辑:

我想我找到了大脑试图重现的答案:Haskell function composition operator of type (c→d) → (a→b→c) → (a→b→d)

答案 2 :(得分:3)

语义编辑器组合器以一种特别简单和美观的方式解决了这个问题。赋予:

你的最终作品如下:

(result.result) nub (++)

答案 3 :(得分:1)

你可以使用看起来有些滑稽的(.).(.)组合器:

Prelude> :set -XNoMonomorphismRestriction
Prelude> :m + Data.List
Prelude Data.List> let f = ((.).(.)) nub (++)
Prelude Data.List> :t f
f :: Eq a => [a] -> [a] -> [a]
Prelude Data.List> f "ab" "ac"
"abc"

但是,在where - 子句中使用lambda或辅助函数可能会更具可读性。

答案 4 :(得分:1)

我不认为您想要的合成运算符作为任何标准库中的单个函数存在。写它的最短方式可能是((.).(.))。使用Functor的{​​{1}}定义,您也可以将其写为((->) t),或者如果您愿意fmap . fmap

上述所有内容都非常神秘,但这个成语很常见,很多人都会认出你在做什么。

顺便说一句,你可能想避免在Haskell中调用两个参数“dyadic”的函数,因为如果你将这个术语扩展到一个参数的函数,你将真的混淆了人。

有关相关讨论,另请参阅this question

您还可以在此库中找到lots of combinators with very intuitive names