我想做一些相当简单的事情; 我使用运算符(++)与Data.Map insertWith ,它工作正常,但我想消除创建的值中的重复,所以想要用小块组成它。
我试过(nub(++)),(nub $(++)),(nub。(++)),一切都无济于事,因为(++)的类型与预期的不匹配小块的类型([a])。
我当然可以定义一个辅助函数或一个lambda,但我认为可能会有一个更清晰的组合。
请提示!
答案 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)
您要求提供无点版本(不提及a
和b
变量)。让我们一个接一个地尝试消除它们。我们将从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。