假设,在 Haskell 中,我有一堆函数都依赖于相同的参数类型:
f :: Par -> a -> b
g :: Par -> b -> c
由于我正在编写更多仍然依赖于这个参数类型的函数,我可以做一些类似的事情
h :: Par -> a -> c
h par = myg . myf
where myf = f par
myg = g par
但是我一直不得不写这些
where
行。问题是:这能避免吗?[编辑:我试图提供一个最小的例子来说明问题,但显然这个例子太少了,无法说明我想要什么。在实际问题中,h当然不仅仅是f和g的组合。所以这里是一些实际的代码:
有功能
apply :: ChamberLattice -> ChLatword -> ChLatWord
reduce :: ChamberLattice -> ChLatWord -> ChLatWord
我正在定义一个函数
chaseTurn :: ChamberLattice -> Turn -> Parity -> ChLatWord -> ChLatWord
chaseTurn cl Straight _ xs = xs
chaseTurn cl t parity xs = if ((turn parity xs) == t)
then case myApply xs of
(y1:y2:ys) -> (y1:y2:(myChaseTurn t parity ys))
ys -> ys
else myReduce xs
where myApply = apply cl
myChaseTurn = chaseTurn cl
myReduce = reduce cl
]
(这个问题本质上是一样的
Grouping functions in Haskell
但在那里我用了一些让人们分心的不幸词。)
最佳答案
您经常使用 h par = f par . g par
,而 par
内容开始变得困惑。
您不能执行 h = f . g
,因为 par
参数也必须传递。
因此,您想出了一个强大的组合运算符来为您执行此操作:
-- (.) :: (b -> c) -> (a -> b) -> a -> c
(§) :: (par -> b -> c) -> (par -> a -> b) -> par -> a -> c
(§) f g par = f par . g par
现在您可以执行
h = f § g
。这个运算符可能是以前发明的。顺便说一下,部分应用的函数是 instances of Monad 。这意味着您可以:
(§) f g par = (do { fpar <- f; gpar <- g; return (fpar . gpar) }) par
要不就:
(§) f g = do { fpar <- f; gpar <- g; return (fpar . gpar) }
(这里,
fpar
是应用了隐式 f
的 par
。monad 实例使 par
隐式。)如果我们要参数化这个 do-block:
(§) f g = ( \f m1 m2 -> do { x1 <- m1; x2 <- m2; return (f x1 x2) } ) (.) f g
和 eta-reduce 参数:
(§) = ( \f m1 m2 -> do { x1 <- m1; x2 <- m2; return (f x1 x2) } ) (.)
在 Hoogle 上查找类似 do-block 的内容,您会发现
liftM2
:(§) = liftM2 (.)
此时我们真的不需要给它一个特殊的名字,因为
liftM2 (.)
已经很短了。关于function - 在 Haskell 中部分应用几个函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49897341/