假设,在 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 是应用了隐式 fpar。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/

10-10 18:24