haskell 有没有一种方法可以用Hana来表达函数application operator/function?

bihw5rsg  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(100)

我的问题

我指的是一个函数,它本质上做了以下事情(模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中编写fidx时,争论你是传递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中的plus1id3id 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 == fid(gidx),但我相信这与问题无关。

vptzau2j

vptzau2j1#

Eureka !
这里有一个oneliner,似乎是一个非常简洁的解决方案:

constexpr auto identity = overload(id, apply);

字符串
其中仅使用Hana函数,即

using boost::hana::apply;
using boost::hana::id;
using boost::hana::overload;


我还没有彻底测试过它,但至少在一些简单的情况下,它似乎是有效的:

assert(21 == identity(21));
assert(21 == identity(times3, 7));
assert(21 == identity(times3)(7));


像上面一样定义了identitythrush很容易实现:

constexpr auto thrush = curry<2>(flip(identity));

assert(21 == thrush(7, times3));
assert(21 == thrush(7)(times3));


Compiler Explorer
上面定义的identity函数与此非常相似,模完美转发和其他细节(当尝试apply成员函数时,这可能变得重要),

constexpr auto identity = [](auto const& x, auto const&... xs) {
    if constexpr (sizeof...(xs) == 0) {
        return x;
    } else {
        return x(xs...);
    }
};

相关问题