我的问题
我指的是一个函数,它本质上做了以下事情(模const
,&
,完美转发,或任何合适的):
auto constexpr dollar = [](auto f, auto x){ return f(x); }; // Why calling it "dollar"? Keep reading...
字符串
这样的函数只能通过Boost.Hana来表达吗?
为什么我会想到这个?
在Haskell中,存在这样一个函数,它被称为($)
(中缀形式的$
),其定义如下(源代码)
($) :: forall r a (b :: TYPE r). (a -> b) -> a -> b
f $ x = f x
型
你可以把第二行简单地写成下面的任何一行
(f $) = f
($) f = f
型
其中第二种形式使得($)
与id
(恒等函数)基本相同是显而易见的,
id :: a -> a
id x = x
型
只需要一个签名,强制第一个参数是函数类型a -> b
。
实际上,在Haskell中将f
应用到x
也可以通过编写以下代码来完成:
f `id` x
型
即使用id
而不是$
。
这和哈娜有什么关系?
由于Hana * 确实 * 提供了一个id
函数,我想知道是否可以使用它(可能与其他东西一起)来定义一个函数应用程序实用程序,而无需在本文顶部手动编写lambda。
困难的部分
这里困难的部分是,当你在Haskell中编写f
idx
时,争论你是传递1个参数还是2个参数给id
并没有什么意义,因为所有的函数都是默认的。
但在C++中却不是这样。例如,我可以这样做:
#include <boost/hana/functional/id.hpp>
#include <iostream>
using boost::hana::id;
int main() {
auto plus1 = [](int x){ return x + 1; };
std::cout << id(plus1)(3) << std::endl; // prints 4
}
型
这看起来很像id
是curried的,并且被一个接一个地而不是一起给予两个输入,但这不是真的。只是id(plus1)
返回plus1
,它被3
馈送。我不知道如何获得 * 以下 *(相当于Haskell中的plus1
id3
或id plus1 3
)工作:
std::cout << id(plus1, 3) << std::endl; // doesn't even compile obviously
型
谜题的真正起源
在阅读To Mock a Mockingbird之后,我想知道:“我如何在C++中仅用Boost.Hana实现Thrush?”(而Thrush是函数应用操作符的boost::hana::flip
版本。)
在现实中,如果想要编写应用程序链,这并不完全相同,因为这两个运算符具有不同的结合性,所以f $ g $ x == f
id(g
idx)
,但我相信这与问题无关。
1条答案
按热度按时间vptzau2j1#
Eureka !
这里有一个oneliner,似乎是一个非常简洁的解决方案:
字符串
其中仅使用Hana函数,即
型
我还没有彻底测试过它,但至少在一些简单的情况下,它似乎是有效的:
型
像上面一样定义了
identity
,thrush
很容易实现:型
(Compiler Explorer)
上面定义的
identity
函数与此非常相似,模完美转发和其他细节(当尝试apply
成员函数时,这可能变得重要),型