我有这个功能
rulesApply :: [PhrasePair] -> Phrase -> Phrase
rulesApply pp = try (transformationsApply "*" reflect pp )
我想学习如何使它无点。
try :: (a -> Maybe a) -> a -> a
try f x = maybe x id (f x)
transformationsApply :: Eq a => a -> ([a] -> [a]) -> ([([a], [a])] -> ([a] -> Maybe [a]))
transformationsApply wc f pfPair list = foldr1 orElse (map (transformationApply wc f list) pfPair)
rulesApply pp = try (transformationsApply "*" reflect pp )
(transformationsApply "*" reflect ) pp
的类型为Eq a => ([([a], [a])] -> ([a] -> Maybe [a]))
我们看到了
try :: (a -> Maybe a) -> a -> a
所以尝试将函数(a -> Maybe a)
作为参数。我们看到(transformationsApply "*" reflect ) pp
的返回类型为([a] -> Maybe [a]))
,因此我们应该可以写。
rulesApply pp = try . (transformationsApply "*" reflect) pp
但这会产生编译错误。
答案 0 :(得分:9)
每当你有一些看起来像
的东西\x -> f (g x)
你可以把它变成
f . g
在这种情况下,你有
s x = f (g x )
rulesApply pp = try (transformationsApply "*" reflect pp )
可以转换(通过将参数移动到等式的另一侧)到
s = \x -> f (g x )
rulesApply = \pp -> try (transformationsApply "*" reflect pp )
反过来,根据我们的规则,
s = f . g
rulesApply = try . transformationsApply "*" reflect
答案 1 :(得分:7)
删除积分相对容易,但你应该逐步移动。
rulesApply pp = try ( transformationsApply "*" reflect pp)
=== [partial application]
rulesApply pp = try ((transformationsApply "*" reflect) pp)
=== [definition of (.)]
rulesApply pp = (try . transformationsApply "*" reflect) pp
=== [eta reduction]
rulesApply = try . transformationsApply "*" reflect
答案 2 :(得分:1)
实际上这很简单:
rulesApply :: [PhrasePair] -> Phrase -> Phrase
rulesApply = try . transformationsApply "*" reflect
无点编程不只是关于美学。它是关于在更高层次上解决问题:不是对函数变量进行操作,而是对函数本身进行操作,从而消除了整个问题区域。
让我们分析(.)
运算符的签名。
(.) :: (b -> c) -> (a -> b) -> (a -> c)
我故意将大括号括在a -> c
周围,以明确它需要两个函数才能生成另一个函数。在这方面,它与原始值上的任何运算符没有太大区别,例如:
(+) :: Int -> Int -> Int
现在,不要沉迷于它,不要指望它适合你的道路上的任何问题。它只是口袋里的另一个工具,应该适当使用。 最常见的用法是避免冗余的lambdas。以下是一些例子:
putStrLn . (++ "!") == \a -> putStrLn (a ++ "!")
void . return == \a -> return a >> return ()
第二个例子基本上相当于const (return ()) == \a -> return ()
,但出于美学原因我更喜欢它。我认为,编译器无论如何都会优化这些东西。