哈斯克尔中的无点风格编程



我有这个函数

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

所以 try 将函数(a -> Maybe a)作为参数。 我们看到(transformationsApply "*" reflect ) pp的返回类型是([a] -> Maybe [a])),所以我们应该能够编写。

rulesApply pp = try . (transformationsApply "*" reflect) pp

但这会产生编译错误。

每当你有看起来像的东西

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

删除点相对容易,但您应该逐步移动。

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

实际上非常简单:

rulesApply :: [PhrasePair] -> Phrase ->  Phrase
rulesApply = try . transformationsApply "*" reflect

无点编程不仅仅是关于美学。这是关于在更高层次上处理问题:你不是对函数变量进行操作,而是对函数本身进行操作,从而消除了整个问题区域。

让我们分析一下(.)运算符的签名。

(.) :: (b -> c) -> (a -> b) -> (a -> c)

我故意在a -> c周围放大括号,以明确表示产生另一个函数需要两个函数。在这方面,它与基元值上的任何运算符没有太大区别,例如:

(+) :: Int -> Int -> Int

现在,不要沉迷于它,也不要指望它会适合你道路上的任何问题。这只是您口袋里的另一个工具,应该适当使用。最常见的用法是避免冗余的lambda。以下是一些示例:

putStrLn . (++ "!") == a -> putStrLn (a ++ "!")
void . return == a -> return a >> return ()

第二个例子基本上相当于const (return ()) == a -> return (),但出于美学原因,我更喜欢它。我认为,编译器无论如何都会优化这些东西。

最新更新