Skip to content

Instantly share code, notes, and snippets.

@drchaos
Last active January 6, 2020 08:12
Show Gist options
  • Save drchaos/3e5834472fee96f2331f33a16f1cae53 to your computer and use it in GitHub Desktop.
Save drchaos/3e5834472fee96f2331f33a16f1cae53 to your computer and use it in GitHub Desktop.
Maybe examples
#include
#include
#include
#include
#include
#include
#include
/* fmap definitions */
struct fmap_base
{
struct none_value {};
template <typename just_t>
struct just
{
just_t m_just;
template<typename... params_t>
just(params_t&&... pp) : m_just{ std::forward<params_t>(pp)... } {}
template<typename unused_param_t>
const just_t& operator()(unused_param_t&&) const { return m_just; }
};
template <>
struct just<none_value>
{
template<typename... params_t>
just(params_t&&... pp) {}
none_value operator()() const { return none_value{}; }
};
template <typename res_t, typename intermediate_res_t>
struct fmap_failed
{
fmap_failed(res_t& ret, intermediate_res_t&&)
{
ret = res_t{};
}
};
};
template
struct fmap : public fmap_base
{
private:
template <typename intermediate_res_t, typename fn_t, typename... functors>
struct fmap_
{
fmap_(res_t& ret, intermediate_res_t&& r, fn_t&& fn, functors&&... ff)
{
if (auto r1 = fn(std::forward<intermediate_res_t>(r)))
{
fmap_<decltype(r1), functors...>(ret, std::move(r1), std::forward<functors>(ff)...);
}
else
{
fmap_failed<res_t, decltype(r1)>( ret, std::move(r1));
};
}
};
template <typename intermediate_res_t, typename fn_t>
struct fmap_<intermediate_res_t, fn_t>
{
fmap_(res_t& ret, intermediate_res_t&& r, fn_t&& fn)
{
ret = fn(std::forward<intermediate_res_t>(r));
}
};
public:
template <typename... functors>
fmap(res_t& ret, functors&&...ff) {
fmap_{ ret,
none_value{},
std::forward<functors>(ff)... };
}
};
/* usage definitions,
I use separate types for each stage just for illutrative purposes
*/
struct search_pattern : public std::string
{
using std::string::string;
operator bool() const { return !empty(); }
};
struct found_param : std::optionalstd::size_t
{
using std::optionalstd::size_t::optional;
// no need to define operator bool() as we borrow it from optional
};
struct found_value : std::optionalstd::string
{
using std::optionalstd::string::optional;
// no need to define operator bool() as we borrow it from optional
};
struct param_list {
std::array<std::pair<const char*, const char*>, 1> m_storage{ std::make_pair("good_pattern", "value") };
};
found_param find_param(const search_pattern& p, const param_list& params)
{
return params.m_storage[0].first == p ? found_param{ 0 } : found_param{};
}
found_value find_env_var(const found_param& v, const param_list& params)
{
// we do not attempt to validate if v contains valid index to illustrate it would never be called if p was not found before
return found_value{ params.m_storage[*v].second };
}
int main()
{
param_list params{};
found_value good_res{}, bad_res{};
fmap<found_value>{ good_res, // <- contains "value" at exit
fmap<found_value>::just<search_pattern>("good_pattern")
, [&params](const search_pattern& p) -> auto { return find_param(p, params); }
, [&params](const found_param& p) -> auto { return find_env_var(p, params); }
};
fmap<found_value>{ bad_res, // <- contains nothing at exit
fmap<found_value>::just<search_pattern>("bad_pattern")
,[&params](const search_pattern& p) -> auto { return find_param(p, params); }
,[&params](const found_param& p) -> auto { return find_env_var(p, params); }
};
}
-- Вариант с последовательным поиском
lookupParam :: String -> [(String,String)] -> Maybe String
-- реализация
lookupEnvVar :: String -> [(String,String)] -> Maybe String
-- реализация
seqLookup :: String -> [(String,String)] -> [(String,String)] -> Maybe String
seqLookup paramName params envVars = do
envVarName <- lookupParam paramName params
value <- lookupEnvVar envVarName envVars
return value
-- Вариант с альтернативным поиском
altLookup :: String -> [(String,String)] -> [(String,String)] -> Maybe String
altLookup paramName = lookupParam paramName params <|> envVarName paramName params
-- или
altLookup' :: String -> [(String,String)] -> [(String,String)] -> Maybe String
altLookup' paramName = asum [ lookupParam paramName params
, envVarName paramName params
]
-- тут `asum` это просто свёртка списка с помощью `<|>`
-- `foldr (<|>) empty l`, где empty - это Nothing для нашего случая, а l - и есть наш список
-- этот вариант интереснее тем, что явно виден порядок альтернатив поиска и этот список проще расширять
-- Другая интересная штука, что благодаря ленивости если первый поиск удачен, то второй не будет вызван никогда
@serhiiprokhorov
Copy link

`#include
#include
#include
#include
#include
#include
#include

/* fmap definitions */

struct fmap_base
{
struct none_value {};

template <typename just_t>
struct just
{
    just_t m_just;

    template<typename... params_t>
    just(params_t&&... pp) : m_just{ std::forward<params_t>(pp)... } {}

    template<typename unused_param_t>
    const just_t& operator()(unused_param_t&&) const { return m_just; }
};
template <>
struct just<none_value>
{
    template<typename... params_t>
    just(params_t&&... pp) {}

    none_value operator()() const { return none_value{}; }
};

template <typename res_t, typename intermediate_res_t>
struct fmap_failed
{
    fmap_failed(res_t& ret, intermediate_res_t&&)
    {
        ret = res_t{};
    }
};

};

template
struct fmap : public fmap_base
{
private:

template <typename intermediate_res_t, typename fn_t, typename... functors>
struct fmap_
{
    fmap_(res_t& ret, intermediate_res_t&& r, fn_t&& fn, functors&&... ff)
    {
        if (auto r1 = fn(std::forward<intermediate_res_t>(r)))
        {         
            fmap_<decltype(r1), functors...>(ret, std::move(r1), std::forward<functors>(ff)...); 
        } 
        else 
        { 
            fmap_failed<res_t, decltype(r1)>( ret, std::move(r1)); 
        };
    }
};

template <typename intermediate_res_t, typename fn_t>
struct fmap_<intermediate_res_t, fn_t>
{
    fmap_(res_t& ret, intermediate_res_t&& r, fn_t&& fn)
    {
        ret = fn(std::forward<intermediate_res_t>(r));
    }
};

public:

template <typename... functors> 
fmap(res_t& ret, functors&&...ff) { 
    fmap_{ ret, 
        none_value{},
        std::forward<functors>(ff)... }; 
}

};

/* usage definitions,
I use separate types for each stage just for illutrative purposes
*/

struct search_pattern : public std::string
{
using std::string::string;

operator bool() const { return !empty(); }

};

struct found_param : std::optionalstd::size_t
{
using std::optionalstd::size_t::optional;

// no need to define operator bool() as we borrow it from optional

};

struct found_value : std::optionalstd::string
{
using std::optionalstd::string::optional;

// no need to define operator bool() as we borrow it from optional

};

struct param_list {
std::array<std::pair<const char*, const char*>, 1> m_storage{ std::make_pair("good_pattern", "value") };
};

found_param find_param(const search_pattern& p, const param_list& params)
{
return params.m_storage[0].first == p ? found_param{ 0 } : found_param{};
}

found_value find_env_var(const found_param& v, const param_list& params)
{
// we do not attempt to validate if v contains valid index to illustrate it would never be called if p was not found before
return found_value{ params.m_storage[*v].second };
}

int main()
{
param_list params{};

found_value good_res{}, bad_res{};

fmap<found_value>{ good_res, // <- contains "value" at exit
      fmap<found_value>::just<search_pattern>("good_pattern")
    , [&params](const search_pattern& p) -> auto { return find_param(p, params); }
    , [&params](const found_param& p) -> auto { return find_env_var(p, params); }
};

fmap<found_value>{ bad_res, // <- contains nothing at exit
      fmap<found_value>::just<search_pattern>("bad_pattern")
    ,[&params](const search_pattern& p) -> auto { return find_param(p, params); }
    ,[&params](const found_param& p) -> auto { return find_env_var(p, params); }
};

}
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment