Haskell benzeri işlev oluşturma işlevi

Sep 12 2020

Bu soruya çok benzer şekilde, C ++ 'da Haskell'in (.)işlevine olabildiğince benzeyebilecek bir şey yazmaya çalışıyorum , bu temelde Bölüm 1'in Bartosz Milewski'nin Programcılar için Kategori Teorisi'nden ikinci alıştırmasıdır .

Kimlik işlevini yazmakla ilgili bu benzer soru da bir referans görevi gördü.

StackOverflow'daki bu yanıt,decltype lambdas autoparametrelerinde decltypekullanılanın şablon parametrelerinde kullanılana eşdeğer olduğunu bana güvence verdi .

Ve bulduğum şey bu:

static constexpr struct compose_t {
    template <typename F, typename G>
    constexpr decltype(auto) operator()(F&& f, G&& g) const noexcept {
        return [&f,&g](auto&& x){
            return f(g(std::forward<decltype(x)>(x)));
        };
    }
} compose;

Bazı düşünceler:

  • operator()referans olarak alır fve ggeri dönen lambda bunları referans olarak yakalar; ve bu seçimi, devletsiz olmayan çağrıları daha ucuza aktarması gerektiğini düşünerek yaptım, ancak doğru seçimi yaptığımdan emin değilim . Bir başka referans da bu .
  • Ben referans olarak bunları geçiyorum beri, arasında seçim yapmak zorunda const&ve &&, ve ben temelde rastgele seçtim.
  • Haskell'inki ile uyumlu bir ikili fonksiyon bileşimi "operatörü" istediğim için, varyadiklerle ilgilenmedim (.) :: (b -> c) -> (a -> b) -> a -> c.
  • composeBaşka bir şeyle beste yapamam çünkü o ikili, uygulama örtük olarak bunu varsayar Fve Gtekildir. Sanırım compose(compose,compose)( (.).(.)Haskell'de olan) gibi bir şeyi mümkün kılmak, kısmi bir uygulama "tesisine" bağlı.

Bu, test etmeye çalıştığım bir kod:

#include <cassert>
#include <utility>

// ... the code from above

static constexpr struct changesign_t {
    template<typename T>
    constexpr decltype(auto) operator()(T&& t) const noexcept { return -t; };
} changesign;

int square(int x) { return x*x; }
int twice(int x) { return 2*x; }

int main() {
    assert(compose(square,twice)(3) == 36);
    assert(compose([](int x){ return x*x; },[](int x){ return 2*x; })(3) == 36);
    assert(compose(changesign, compose([](auto x){ return x*x; }, [](auto x){ return 2*x; }))(3) == -36);
}

Yanıtlar

3 G.Sliepen Oct 07 2020 at 22:38

Bir kullanmaya gerek yoktur struct compose_tsarmak için operator(), sadece taşıyabilirsiniz operator()bunun dışında ve yeniden adlandırın compose():

template <typename F, typename G>
constexpr decltype(auto) compose(F&& f, G&& g) noexcept {
    return [&f,&g](auto&& x){
        return f(g(std::forward<decltype(x)>(x)));
    };
}

Şimdi, bahsettiğiniz bu yazıda yazılan koda çok daha yakın , ancak elbette sadece iki tekli işlevi oluşturmakla sınırlısınız.

Bunun dışında, sahip olduğunuz kısıtlamalarla yaşayabilirseniz, uygulamanızda yanlış bir şey görmüyorum.