How can i use ramda.js with this code?

时间:2018-04-17 01:38:25

标签: javascript functional-programming ramda.js

I am beginning to use ramda, but have doubts about how to implement functions ramda.

This code is to mount a select object to do queries for sequelize.

See code:

#include "stdafx.h"
//#include "utilities.h"
#include <cstdlib>
#include <iostream>
#include <tuple>

//https://stackoverflow.com/questions/26902633/how-to-iterate-over-a-stdtuple-in-c-11
template<class F, class...Ts, std::size_t...Is>
void for_each_in_tuple(const std::tuple<Ts...> & tuple, F func, std::index_sequence<Is...>) {
    using expander = int[];
    (void)expander {
        0, ((void)func(std::get<Is>(tuple)), 0)...
    };
}

template<class F, class...Ts>
void for_each_in_tuple( std::tuple<Ts...> & tuple, F func) {
    for_each_in_tuple(tuple, func, std::make_index_sequence<sizeof...(Ts)>());
}


// https://stackoverflow.com/questions/42255534 (Yakk)
namespace notstd {
    template<class T> struct tag_t { constexpr tag_t() {}; using type = T; };
    template<class T> constexpr tag_t<T> tag{};
    template<class Tag> using type_t = typename Tag::type;

    template<class...Ts, class F>
    void for_each_type(F&& f) {
        using discard = int[];
        (void)discard {
            0, (void(
                f(tag<Ts>)
                ), 0)...
        };
    }
}

// A component
class icomponent {
public:
    virtual std::string id() = 0;
    virtual ~icomponent() = default;

    virtual void init() = 0;
    virtual void dispose() = 0;

    void say() const {
        std::cout << "say: " << typeid(*this).name() << " ANDNAME: " << /*id( ).c_str( )*/"???" << std::endl;
    }
};

class component_base : public icomponent
{
public:
    virtual ~component_base() = default;

    virtual void init()
    {
        // ... init context
    }

    virtual void dispose()
    {
        // ...
    }

    // ... more
};

// Sample components
class component_a : public component_base {
public:
    virtual std::string id() override { return "component a"; }
};
class component_b : public component_base {
public:
    virtual std::string id() override { return "component b"; }
};
class component_c : public component_base {
public:
    virtual std::string id() override { return "component c"; }
};

// Interface component manager
class iprocessing_component_manager {
public:
    virtual ~iprocessing_component_manager() = default;

    virtual void init() = 0;
    virtual icomponent* prepare() = 0;
    virtual void recycle(icomponent* p) = 0;
    virtual void dispose() = 0;
};

// Implementation component manager
template<typename T>
class  type_processing_component_manager
    : public iprocessing_component_manager {
public:
    virtual ~type_processing_component_manager() = default;

    virtual T* prepare() override
    {
        // Default create T or fetch from a object pool, etc ...
        return new T;
    }
};

// Implementation virt. methods component mgr
template<typename ... Ts>
class tuple_processing_component_manager
    : public type_processing_component_manager<Ts>... {
public:
    virtual ~tuple_processing_component_manager() = default;

    virtual void init() override
    {
        std::cout << "init: " << typeid(*this).name() << std::endl;

    }

    template<typename T>
    T* prepare()
    {
        return type_processing_component_manager<T>::prepare();
    }

    virtual void recycle(icomponent* p) override
    {
        // Delete pointer or return to an object pool, etc
        delete p;
    }

    virtual void dispose() override
    {

    }
};

// The controller
template <typename... Ts>
class controller  {

    std::tuple< Ts...> tups;

public:
    controller()
    {
    }
    ~controller() = default;

    // Do some initialization
    // https://stackoverflow.com/questions/16387354/template-tuple-calling-a-function-on-each-element
    void init()
    {
        for_each_in_tuple(tups, [](auto &x) { x.say(); });
//      m_component_manager->init();
    }

    // Process components
    void process()
    {
        // A simple loop over components. 

        //but this does not get the stored objects!
        //notstd::for_each_type<Ts...>([&](auto tag) {
        //  using component_t = notstd::type_t<decltype(tag)>;

    }

    // ... more stuff
};

int main(int argc, char** argv)
{
    controller<component_a, component_c> c;
    c.init();
    c.process();

    return 0;
}

Or see demo on link

http://jsbin.com/zerahay/edit?js,console,output

2 个答案:

答案 0 :(得分:1)

我有点犹豫,只是简单地回应一个已翻译的代码块,我的学习建议将是尝试用Ramda的那些逐一替换你已经拥有的功能。

除了犹豫之外,下面提供了一个示例,说明了使用Ramda的各种函数时代码的外观。

// The existing check for `!!string.length` allows for potential issues with
// arrays being passed in and incorrectly validating, so this will ensure the
// value is indeed a string before checking its length

const stringRequired = R.both(R.is(String), R.complement(R.isEmpty))

// `addFilter` produces a function that takes an object and uses the provided
// function to validate the value associated with the provided key if it exists
// otherwise using the provided `initial` value. If valid, an object containing
// the key and value will be returned, otherwise an empty object is returned.

const addFilter = (validate, initial, key) =>
  R.pipe(
    R.propOr(initial, key),
    R.ifElse(validate, R.objOf(key), R.always({}))
  )

// `selector` takes an object and passes it to each function generated by
// calling `addFilter`, merging the resulting objects together.

const selector = (q = {}) =>
  R.converge(R.merge, [
    addFilter(stringRequired, '', 'name'),
    addFilter(Number.isInteger, 10, 'limit')
  ])(q)

console.log(selector())
console.log(selector({ name: 'David Costa' }))
console.log(selector({ limit: 50 }))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

答案 1 :(得分:1)

为什么?

我认为你需要考虑为什么你想把它转换成Ramda (免责声明:我是Ramda的作者)Ramda是一个图书馆,一个工具包。在它有助于清理代码或者更容易理解问题及其解决方案时使用它。如果没有,请不要使用它。

那就是说,我使用Ramda重构了它:

重构

我只是试着重构一下。最后,我将所有辅助函数替换为一个辅助函数,其中包含['limit', 10, numberRequired]等条件列表,以创建与selector等效的函数。

我确实沿途使用了一些Ramda函数,但是唯一提供实质性帮助的函数是assoc,它创建了一个旧对象以及一个键和值。例如,使用compose(Boolean, length)const stringRequired = string => !!string.length更清晰,但这并不是一个很大的区别。

在我看来,重要的变化是makeSelector函数,这使得创建selector函数更具说明性。这有点难看,如果我从头开始,我可能会以不同的方式编写它,但我在一系列步骤中完成了这一步,内联你的辅助函数,直到我有一个相同行为的相当短的函数。

// rules
const stringRequired = R.compose(Boolean, R.length)
const numberRequired = number => Number.isInteger(number)


// utils
const makeSelector = (conditions) => (query = {}) => R.reduce(
  (select, [key, initial, validate]) => {
    const value = key in select && validate(select[key]) ? select[key] : initial;
    return validate(value) ? R.assoc(key, value, select) : select
  },
  query,
  conditions
)

// main
const selector = makeSelector([
  ['limit', 10, numberRequired],
  ['name', '', stringRequired]
])

console.log(selector());
console.log(selector({ name: 'David Costa' }));
console.log(selector({ limit: 50 }));
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>