Semantic editor combinators (Part 1)

May 13, 2014

Result

现在要修改一个一元函数的结果,可以这样实现:

result edit f x = edit (f x)

-- or
-- result edif f = edit . f
-- result = (.)

那么修改二元函数的最终结果呢?Haskell里的函数都被柯里化,可以看作一元函数,直接使用一次result看看:

result2 edit f = result useEdit f
  where useEdit = _

这里f是个二元函数,userEdit的参数应该是f用一个参数部分调用后得到闭包,这又是一个一元函数,如果我们用result修改闭包的结果,也就相当于修改原来二元函数的最终结果,所以:

result2 edit f = result useEdit f
  where useEdit closure = result edit closure

再对这个result2进行化简:

result2 edit f = result useEdit f
  where useEdit closure = result edit closure

result2 edit f = result useEdit f
  where useEdit = result edit

result2 edit f = result (result edit) f

result2 edit = result (result edit)

result2 edit = (result . result) edit

resul2 = result . result

同理,对n元函数的最后结果进行修改就是就是n个result的组合。只要result能修改一元函数的结果,以及下面的等价关系,就很易懂了

f . g = \x -> f (g x)

Argument

现在我们要在调用一元函数前,修改它的参数:

arg :: (a -> b) -> (b -> c) -> a -> c
arg edit f x = f (edit x)

-- or
-- arg edif f x = (f . edit) x
-- arg = flip (.)

那么修改二元函数f的第一个参数呢?在Haskell里函数都是一元的,所以用arg就可以了。更有趣的是修改二元函数的第二个参数。要改第二个参数就要先部分调用f得到一个闭包,然后再用arg修改用闭包的第一个参数,所以可以组合resultarg

arg2 = result . arg

同理,修改n元函数的最后一个参数就是 n - 1个resultarg的组合。

如果一个函数的类型是 (a -> b) -> (b -> c) -> c,怎样用b -> b的函数修改第一个参数的结果?

resultOfArg = arg . result

嗯,规律超明显。