haskell中的无点样式编程

时间:2013-11-15 19:42:12

标签: haskell pointfree

我有这个功能

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

但这会产生编译错误。

3 个答案:

答案 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 (),但出于美学原因我更喜欢它。我认为,编译器无论如何都会优化这些东西。