部分评估Haskell中的几个函数 [英] Partially evaluate several functions in Haskell
问题描述
f :: Par - > a - > b
g :: Par - > b - > c
由于我正在编写更多仍然依赖于此参数类型的函数,因此我可以就像
h :: Par - > a - > c
h par = myg。 myf
其中myf = f par
myg = g par par
但是我保留必须写这些其中
行。问题是:这可以避免吗?
<编辑:我试图提供一个最小的例子来说明问题,但显然这个例子太简单了,无法说明我想要的东西。在实际问题中,h当然不仅仅是f和g的组成。所以这里是一些实际的代码:
有函数
apply :: ChamberLattice - > ChLatword - > ChLatWord
reduce :: ChamberLattice - > ChLatWord - > ChLatWord
我正在定义一个函数
chaseTurn :: ChamberLattice - >转 - >奇偶校验 - > ChLatWord - > ChLatWord
chaseTurn cl Straight _ xs = xs
chaseTurn cl t奇偶校验xs = if((turn parity xs)== t)
then case myApply xs
(y1:y2 :ys) - > (y1:y2:(myChaseTurn t parity ys))
ys - > ys
else myReduce xs
where myApply = apply cl
myChaseTurn = chaseTurn cl
myReduce = reduce cl
]
(这个问题与
基本相同在Haskell中对函数进行分组
但在那里我使用了一些让人分心的不幸词语。)
g
: f :: Par - > (a - > b)
g :: Par - > (b - > c)
函数也是类型,所以我们可以任意决定别名 a - > b
到φ
( phi 而不是 f )和 b - > c
到γ
( gamma 而不是 g )。 (是的,当你的信件用完时,你可以使用希腊字母!)
这意味着你可以将你的函数视为具有类型
f :: Par - > φ
g :: Par - > γ
这些都是所谓的 reader monad 的自动实例,这也是一个(应用)函数。特别是( - >)Par
,或者,如果有帮助, Par - >
是 Applicative
实例。这意味着您可以使用纯粹
和<>
。
作为第一次尝试,您可以写一些类似于
pure(\xy - >( x,y))* f * g
为了简单理解该构图如何工作。该表达式的类型为 Par - > (φ,γ)
,可以这么说。 lambda表达式只需从 f
'容器'中取 x
,并且 y $来自
g
'容器'的c $ c>,并将它们组合到一个元组中。元组的第一个元素的类型为φ
,第二个元素的类型为γ
。
插入φ
和γ
的定义,就会得到类型参数 - > (a - > b,b - > c)
。
而不是返回值作为函数的元组,组成这些功能。您可以使用函数组合运算符。
作为:
h =纯的(\ xy - > x。y)* f * g
然而,显式lambda表达式可以被eta简化为:
h =纯(。)* * f * g
最后,不要写 pure(。)*<
您可以使用中缀< $>
运算符:
h =(。)< $> f * g
这个函数的类型是 Par - > a - > c
。
Suppose, in Haskell, I have a bunch of functions that all depend on the same parameter type:
f :: Par -> a -> b
g :: Par -> b -> c
As I'm writing more of these functions that still depend on this parameter type, I can do something like
h :: Par -> a -> c
h par = myg . myf
where myf = f par
myg = g par
However I keep having to write these where
lines. The question is: can this be avoided?
[Edit: I tried to provide a minimal example to illustrate the problem but apparently the example is too minimal to illustrate what I want. In the actual problem h is of course not just the composition of f and g. So here is some actual code:
There are functions
apply :: ChamberLattice -> ChLatword -> ChLatWord
reduce :: ChamberLattice -> ChLatWord -> ChLatWord
and I am defining a function
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
]
(This question is essentially the same as Grouping functions in Haskell but there I used some unfortunate words that distracted people.)
In Haskell, all functions take one input argument. Sometimes, though, the return value of applying a function is a new function. As a first step, then, you can make that more explicit by putting brackets around the return value of your functions f
and g
:
f :: Par -> (a -> b)
g :: Par -> (b -> c)
Functions are types as well, so we could arbitrarily decide to alias a -> b
to φ
(phi instead of f) and b -> c
to γ
(gamma instead of g). (Yes, when you run out of letters, you reach for the Greek alphabet!)
This means that you can view your functions as having the types
f :: Par -> φ
g :: Par -> γ
These are both automatically instances of the so-called reader monad, which is also an (applicative) functor. Particularly, (->) Par
, or, if it helps, Par ->
is an Applicative
instance. This means that you can use pure
and <*>
with it.
As a first attempt, you can write something like
pure (\x y -> (x, y)) <*> f <*> g
in order to simply understand how that composition works. That expression has the type Par -> (φ, γ)
, so to speak. That lambda expression simply takes x
from the f
'container', and y
from the g
'container', and combines them in a tuple. The first element of the tuple has the type φ
, and the second element has the type γ
.
Plugging in the definitions of φ
and γ
, you get the type Par -> (a -> b, b -> c)
.
Instead of a return value as a tuple of functions, you want to compose these functions. You can use the function composition operator .
for that:
h = pure (\x y -> x . y) <*> f <*> g
That explicit lambda expression, though, can be eta-reduced to:
h = pure (.) <*> f <*> g
Finally, instead of writing pure (.) <*>
you can use the infix <$>
operator:
h = (.) <$> f <*> g
This function has the type Par -> a -> c
.
这篇关于部分评估Haskell中的几个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!