我不知道这个应用程序会有多大用处,但我对它很好奇因为这个 C++ 答案 我的一个问题.
所以,给定一个三元
f
和一个二元g
,例如
f x y z = x + 10*y + 100*z
g x y = x + 10*y
如何获得满足以下条件的函数
h
?
h f g 1 2 3 4 5 == (321, 54)
很明显我可以定义
h f g = \x y z v w -> (f x y z, g v w)
但我很想知道是否可以使用一些现有的抽象来以无点风格为每个参数
m
和n
完成。
对于这个具体的例子(
m == 3 && n == 2
)pointfree.io表明结果变得不可读:
h = flip . ((flip . ((flip . (((.) . (.) . (,)) .)) .)) .)
但我仍然很好奇是否存在其他东西。
为了好玩,我尝试机械地应用组合逻辑来推导公式,但仍然只针对
m == 3 && n == 2
的特定情况:
b = (.) -- bluebird (names from "To Mock a Mockingbird")
c = flip -- cardinal (names from "To Mock a Mockingbird")
p = (,)
f x y z = x + 10*y + 100*z
g x y = x + 10*y
{-
p(fxyz)(gvw) = ?xyzvw, with ? in terms of p, f, g and known birds
(p(fxyz))(gvw)
B(B(p(fxyz)))gvw
CBg(B(p(fxyz)))vw
B(CBg)B(p(fxyz))vw
B(B(CBg)B)p(fxyz)vw
B(B(B(CBg)B)p)(fxy)zvw
B(B(B(B(CBg)B)p))(fx)yzvw
B(B(B(B(B(CBg)B)p)))fxyzvw
B(B(B(B(B(CBB)(CB)g)p)))fxyzvw
B(B(B(BB(B(CBB)(CB))gp)))fxyzvw
B(B(BB(BB(B(CBB)(CB))g)p))fxyzvw
B(B(B(BB)(BB(B(CBB)(CB)))gp))fxyzvw
B(BB(B(BB)(BB(B(CBB)(CB)))g)p)fxyzvw
BB(BB(B(BB)(BB(B(CBB)(CB)))g))pfxyzvw
B(BB)(B(BB)(B(BB)(BB(B(CBB)(CB)))))gpfxyzvw
C(C(B(BB)(B(BB)(B(BB)(BB(B(CBB)(CB))))))p)fgxyzvw
-}
h = c (c (b (b b) (b (b b) (b (b b) (b b (b (c b b) (c b)))))) p)
h f g 1 2 3 4 5 == (321, 54) -- True
正如 Willem Van Onsem 在评论中指出的那样,您的问题的问题在于,从技术上讲,Haskell 中的每个函数都只需要一个参数。我知道你的意思,我也知道你想做什么,但是没有理由为什么
(+)
不能只是一个返回函数的单参数函数而不是一个双参数函数。事实上,如果我们为 Num
定义一个 Int -> Int
实例,那么 (+)
完全有可能是一个三参数函数!
另一方面,仅仅因为参数的数量无法推断,并不意味着你就完蛋了。如果你愿意给 GHC 一些提示,你可以在类型级别做你想做的事。考虑以下几点:
data Nat = Zero | Succ Nat
type One = Succ Zero
type Two = Succ One
type Three = Succ Two
type Four = Succ Three
class NFun m n f g where
type family FunT m n f g
h :: f -> g -> FunT m n f g
instance NFun m n x y => NFun (Succ m) n (a -> x) y where
type FunT (Succ m) n (a -> x) y = a -> FunT m n x y
h f g a = h @m @n (f a) g
instance NFun Zero n x y => NFun Zero (Succ n) x (a -> y) where
type FunT Zero (Succ n) x (a -> y) = a -> FunT Zero n x y
h f g a = h @Zero @n f (g a)
instance NFun Zero Zero x y where
type FunT Zero Zero x y = (x,y)
h = (,)
(这可能可以使用 GHC 的 TypeLits 完成得更漂亮,但我总是难以解决归纳问题,所以我自己滚动了自然数。)
在这里,我定义了一个类型类
NFun
,它采用两个数字类型,指示函数将采用多少个参数。第一个实例为第一个函数提供参数,第二个实例为第二个函数提供参数。最终实例对结果进行配对。
你可以这样使用它:
f x y z = x + 10*y + 100*z
g x y = x + 10*y
h @Three @Two f g 1 2 3 4 5 == (321, 54)