607 lines
22 KiB
C++
Executable File
607 lines
22 KiB
C++
Executable File
// Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
|
|
// https://github.com/Dobiasd/FunctionalPlus
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#pragma once
|
|
|
|
#include <fplus/composition.hpp>
|
|
#include <fplus/container_common.hpp>
|
|
#include <fplus/pairs.hpp>
|
|
|
|
#include <fplus/internal/invoke.hpp>
|
|
|
|
#include <map>
|
|
#include <unordered_map>
|
|
|
|
namespace fplus
|
|
{
|
|
|
|
// API search type: pairs_to_map : [(key, val)] -> Map key val
|
|
// fwd bind count: 0
|
|
// Converts a Container of pairs (key, value) into a dictionary.
|
|
template <typename MapOut, typename ContainerIn>
|
|
MapOut pairs_to_map(const ContainerIn& pairs)
|
|
{
|
|
return convert_container_and_elems<MapOut>(pairs);
|
|
}
|
|
|
|
// API search type: pairs_to_map_grouped : [(key, val)] -> Map key [val]
|
|
// fwd bind count: 0
|
|
// Convert a list of key-value pairs to a dictionary
|
|
// while pushing values having the same key into a vector.
|
|
// pairs_to_map_grouped([("a", 1), ("a", 2), ("b", 6), ("a", 4)])
|
|
// -> {"a": [1, 2, 4], "b": [6]}
|
|
template <typename ContainerIn,
|
|
typename Key = typename ContainerIn::value_type::first_type,
|
|
typename SingleValue = typename ContainerIn::value_type::second_type,
|
|
typename MapOut = std::map<Key, std::vector<SingleValue>>>
|
|
MapOut pairs_to_map_grouped(const ContainerIn& pairs)
|
|
{
|
|
MapOut result;
|
|
for (const auto& p : pairs)
|
|
{
|
|
result[p.first].push_back(p.second);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// API search type: map_to_pairs : Map key val -> [(key, val)]
|
|
// fwd bind count: 0
|
|
// Converts a dictionary into a Container of pairs (key, value).
|
|
template <typename MapType,
|
|
typename MapPair = typename MapType::value_type,
|
|
typename Key = typename std::remove_const<typename MapPair::first_type>::type,
|
|
typename Val = typename std::remove_const<typename MapPair::second_type>::type,
|
|
typename OutPair = std::pair<Key, Val>,
|
|
typename ContainerOut = std::vector<OutPair>>
|
|
ContainerOut map_to_pairs(const MapType& dict)
|
|
{
|
|
return convert_container_and_elems<ContainerOut>(dict);
|
|
}
|
|
|
|
// API search type: transform_map_values : ((old_val -> new_val), Map key old_val) -> Map key new_val
|
|
// fwd bind count: 1
|
|
// Manipulate the values in a dictionary, keeping the key-value relationship.
|
|
// transform_map_values((*2), {0: 2, 1: 3}) == {0: 4, 1: 6}
|
|
template <typename F, typename MapIn>
|
|
auto transform_map_values(F f, const MapIn& map)
|
|
{
|
|
using MapInPair = typename MapIn::value_type;
|
|
using Key = std::remove_const_t<typename MapInPair::first_type>;
|
|
using InVal = std::remove_const_t<typename MapInPair::second_type>;
|
|
using OutVal = std::decay_t<internal::invoke_result_t<F, InVal>>;
|
|
using MapOut = typename internal::SameMapTypeNewTypes<MapIn, Key, OutVal>::type;
|
|
|
|
return pairs_to_map<MapOut>(
|
|
transform(
|
|
bind_1st_of_2(transform_snd<Key, InVal, F>, f),
|
|
map_to_pairs(map)));
|
|
}
|
|
|
|
// API search type: map_union_with : (((val, val) -> val), Map key val, Map key val) -> Map key val
|
|
// fwd bind count: 2
|
|
// Combine two dictionaries using a binary function for the values.
|
|
// map_union_with((++), {0: a, 1: b}, {0: c, 2: d}) == {0: ac, 1: b, 2: d}
|
|
template <typename F, typename MapIn>
|
|
auto map_union_with(F f, const MapIn& dict1, const MapIn& dict2)
|
|
{
|
|
const auto both = append(map_to_pairs(dict1), map_to_pairs(dict2));
|
|
using Key = typename decltype(both)::value_type::first_type;
|
|
using SingleValue = typename decltype(both)::value_type::second_type;
|
|
auto full_map = pairs_to_map_grouped<decltype(both), Key, SingleValue,
|
|
typename internal::SameMapTypeNewTypes<MapIn, Key, std::vector<SingleValue>>::type>(both);
|
|
const auto group_f = [f](const auto& vals)
|
|
{
|
|
return fold_left_1(f, vals);
|
|
};
|
|
return transform_map_values(group_f, full_map);
|
|
}
|
|
|
|
// API search type: map_union : (Map key val, Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Combine two dictionaries keeping the value of the first map
|
|
// in case of key collissions.
|
|
// map_union({0: a, 1: b}, {0: c, 2: d}) == {0: a, 1: b, 2: d}
|
|
template <typename MapType>
|
|
MapType map_union(const MapType& dict1, const MapType& dict2)
|
|
{
|
|
using Value = typename MapType::value_type::second_type;
|
|
|
|
const auto get_first = [](const Value& a, const Value&) -> Value
|
|
{
|
|
return a;
|
|
};
|
|
return map_union_with(get_first, dict1, dict2);
|
|
}
|
|
|
|
// API search type: get_map_keys : Map key val -> [key]
|
|
// fwd bind count: 0
|
|
// Returns all keys used in a map.
|
|
template <typename MapType,
|
|
typename ContainerOut =
|
|
std::vector<typename std::remove_const<typename MapType::key_type>::type>>
|
|
ContainerOut get_map_keys(const MapType& dict)
|
|
{
|
|
auto pairs = map_to_pairs(dict);
|
|
typedef typename decltype(pairs)::value_type::first_type FirstType;
|
|
typedef typename decltype(pairs)::value_type::second_type SecondType;
|
|
return transform_convert<ContainerOut>(
|
|
fst<FirstType, SecondType>, map_to_pairs(dict));
|
|
}
|
|
|
|
// API search type: get_map_values : Map key val -> [val]
|
|
// fwd bind count: 0
|
|
// Returns all values present in a map.
|
|
template <typename MapType,
|
|
typename ContainerOut =
|
|
std::vector<typename std::remove_const<typename MapType::mapped_type>::type>>
|
|
ContainerOut get_map_values(const MapType& dict)
|
|
{
|
|
auto pairs = map_to_pairs(dict);
|
|
typedef typename decltype(pairs)::value_type::first_type FirstType;
|
|
typedef typename decltype(pairs)::value_type::second_type SecondType;
|
|
return transform_convert<ContainerOut>(
|
|
snd<FirstType, SecondType>, map_to_pairs(dict));
|
|
}
|
|
|
|
// API search type: swap_keys_and_values : Map a b -> Map b a
|
|
// fwd bind count: 0
|
|
// Swaps keys and Values of a dict:
|
|
// swap_keys_and_values({1: "a", 2: "b"}) == {"a": 1, "b": 2}
|
|
template <typename MapIn,
|
|
typename MapInPair = typename MapIn::value_type,
|
|
typename InKey = typename MapInPair::first_type,
|
|
typename InVal = typename MapInPair::second_type,
|
|
typename OutKey = InVal,
|
|
typename OutVal = typename std::remove_const<InKey>::type,
|
|
typename MapOut = typename internal::SameMapTypeNewTypes<MapIn, OutKey, OutVal>::type>
|
|
MapOut swap_keys_and_values(const MapIn& dict)
|
|
{
|
|
auto inAsPairs = map_to_pairs(dict);
|
|
auto outAsPairs = transform(swap_pair_elems<InKey, InVal>, inAsPairs);
|
|
return pairs_to_map<MapOut>(outAsPairs);
|
|
}
|
|
|
|
// API search type: create_map : ([key], [val]) -> Map key val
|
|
// fwd bind count: 1
|
|
// Zip a sequence of keys with a sequence of values to obtain a dictionary.
|
|
// create_map([1,2,3], ["one", "two"]) == {1: "one", 2: "two"}
|
|
template <typename ContainerIn1, typename ContainerIn2,
|
|
typename Key = typename std::remove_const<typename ContainerIn1::value_type>::type,
|
|
typename Val = typename std::remove_const<typename ContainerIn2::value_type>::type,
|
|
typename MapOut = std::map<Key, Val>>
|
|
MapOut create_map(const ContainerIn1& keys, const ContainerIn2& values)
|
|
{
|
|
auto pairs = zip(keys, values);
|
|
return pairs_to_map<MapOut>(pairs);
|
|
}
|
|
|
|
// API search type: create_map_with : ((key -> val), [key]) -> Map key val
|
|
// fwd bind count: 1
|
|
// Take a list of keys and create a dictionary
|
|
// generating the values by applying f to each key.
|
|
// create_map_with(show, [1,2]) == {1: "1", 2: "2"}
|
|
template <typename ContainerIn, typename F>
|
|
auto create_map_with(F f, const ContainerIn& keys)
|
|
{
|
|
return create_map(keys, transform(f, keys));
|
|
}
|
|
|
|
// API search type: create_unordered_map : ([key], [val]) -> Map key val
|
|
// fwd bind count: 1
|
|
// Zip a sequence of keys with a sequence of values to obtain a dictionary.
|
|
// create_unordered_map([1,2,3], ["one", "two"]) == {1: "one", 2: "two"}
|
|
template <typename ContainerIn1, typename ContainerIn2,
|
|
typename Key = typename std::remove_const<typename ContainerIn1::value_type>::type,
|
|
typename Val = typename std::remove_const<typename ContainerIn2::value_type>::type,
|
|
typename MapOut = std::unordered_map<Key, Val >>
|
|
MapOut create_unordered_map(
|
|
const ContainerIn1& keys,
|
|
const ContainerIn2& values)
|
|
{
|
|
auto pairs = zip(keys, values);
|
|
return pairs_to_map<MapOut>(pairs);
|
|
}
|
|
|
|
// API search type: create_unordered_map_with : ((key -> val), [key]) -> Map key val
|
|
// fwd bind count: 1
|
|
// Take a list of keys and create a dictionary
|
|
// generating the values by applying f to each key.
|
|
// create_unordered_map_with(show, [1,2]) == {1: "1", 2: "2"}
|
|
template <typename ContainerIn, typename F>
|
|
auto create_unordered_map_with(F f, const ContainerIn& keys)
|
|
{
|
|
return create_unordered_map(keys, transform(f, keys));
|
|
}
|
|
|
|
// API search type: get_from_map : (Map key val, key) -> Maybe val
|
|
// fwd bind count: 1
|
|
// Returns just the value of a key if key is present.
|
|
// Otherwise returns nothing.
|
|
template <typename MapType,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
maybe<Val> get_from_map(const MapType& map, const Key& key)
|
|
{
|
|
auto it = map.find(key);
|
|
if (it == std::end(map))
|
|
return nothing<Val>();
|
|
return just(it->second);
|
|
}
|
|
|
|
// API search type: get_from_map_unsafe : (Map key val, key) -> val
|
|
// fwd bind count: 1
|
|
// Returns the value of a key if key is present.
|
|
// Crashes otherwise.
|
|
template <typename MapType,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
Val get_from_map_unsafe(const MapType& map, const Key& key)
|
|
{
|
|
return unsafe_get_just(get_from_map(map, key));
|
|
}
|
|
|
|
// API search type: get_from_map_with_def : (Map key val, val, key) -> val
|
|
// fwd bind count: 2
|
|
// Returns the value of a key if key is present.
|
|
// Otherwise returns the provided default.
|
|
// Also known as prop_or.
|
|
template <typename MapType,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
Val get_from_map_with_def(const MapType& map, const Val& defVal,
|
|
const Key& key)
|
|
{
|
|
return just_with_default(defVal, get_from_map(map, key));
|
|
}
|
|
|
|
// API search type: get_first_from_map : (Map key val, [key]) -> Maybe val
|
|
// fwd bind count: 1
|
|
// Returns just the value of the first key present.
|
|
// Otherwise returns nothing.
|
|
template <typename MapType,
|
|
typename KeysContainer,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
maybe<Val> get_first_from_map(const MapType& map, const KeysContainer& keys)
|
|
{
|
|
static_assert(std::is_same<typename KeysContainer::value_type, Key>::value,
|
|
"Key type does not match.");
|
|
for (const auto& key: keys)
|
|
{
|
|
auto it = map.find(key);
|
|
if (it != std::end(map))
|
|
return just(it->second);
|
|
}
|
|
return nothing<Val>();
|
|
}
|
|
|
|
// API search type: get_first_from_map_unsafe : (Map key val, [key]) -> val
|
|
// fwd bind count: 1
|
|
// Returns the value of the first key present.
|
|
// Crashes otherwise.
|
|
template <typename MapType,
|
|
typename KeysContainer,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
Val get_first_from_map_unsafe(const MapType& map, const KeysContainer& keys)
|
|
{
|
|
return unsafe_get_just(get_first_from_map(map, keys));
|
|
}
|
|
|
|
// API search type: get_first_from_map_with_def : (Map key val, val, [key]) -> val
|
|
// fwd bind count: 2
|
|
// Returns the value of the first key present.
|
|
// Otherwise returns the provided default.
|
|
template <typename MapType,
|
|
typename KeysContainer,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
Val get_first_from_map_with_def(const MapType& map, const Val& defVal,
|
|
const KeysContainer& keys)
|
|
{
|
|
return just_with_default(defVal, get_first_from_map(map, keys));
|
|
}
|
|
|
|
// API search type: map_contains : (Map key val, key) -> Bool
|
|
// fwd bind count: 1
|
|
// Checks if a map contains a key.
|
|
template <typename MapType, typename Key = typename MapType::key_type>
|
|
bool map_contains(const MapType& map, const Key& key)
|
|
{
|
|
auto it = map.find(key);
|
|
return it != std::end(map);
|
|
}
|
|
|
|
// API search type: map_keep_if : ((key -> Bool), Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Filters the map by keys.
|
|
// map_keep_if(is_upper_case, {a: 1, b: 2, A: 3, C: 4}) == {A: 3, C: 4}
|
|
// Also known as pick_by.
|
|
template <typename MapType, typename Pred>
|
|
MapType map_keep_if(Pred pred, const MapType& map)
|
|
{
|
|
MapType result;
|
|
for (const auto& key_and_value : map)
|
|
{
|
|
if (internal::invoke(pred, key_and_value.first))
|
|
{
|
|
result.insert(key_and_value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// API search type: map_drop_if : ((key -> Bool), Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Filters the map by keys.
|
|
// map_drop_if(is_lower_case, {a: 1, b: 2, A: 3, C: 4}) == {A: 3, C: 4}
|
|
// Inverse of map_keep_if.
|
|
template <typename MapType, typename Pred>
|
|
MapType map_drop_if(Pred pred, const MapType& map)
|
|
{
|
|
return map_keep_if(logical_not(pred), map);
|
|
}
|
|
|
|
// API search type: map_keep : ([key], Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Keeps only the pairs of the map found in the key list.
|
|
// map_keep([a, d], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
|
|
// map_keep([a, e, f], {a: 1, b: 2, c: 3, d: 4}) == {a: 1}
|
|
// Also known as pick.
|
|
template <typename MapType, typename KeyContainer>
|
|
MapType map_keep(const KeyContainer& keys, const MapType& map)
|
|
{
|
|
static_assert(std::is_same<
|
|
typename KeyContainer::value_type,
|
|
typename MapType::key_type>::value,
|
|
"Key types do not match.");
|
|
return map_keep_if(bind_2nd_of_2(is_elem_of<KeyContainer>, keys), map);
|
|
}
|
|
|
|
// API search type: map_drop : ([key], Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Keeps only the pairs of the map not found in the key list.
|
|
// Inverse of map_keep.
|
|
// map_drop([b, c], {a: 1, b: 2, c: 3, d: 4}); == {a: 1, d: 4}
|
|
template <typename MapType, typename KeyContainer>
|
|
MapType map_drop(const KeyContainer& keys, const MapType& map)
|
|
{
|
|
static_assert(std::is_same<
|
|
typename KeyContainer::value_type,
|
|
typename MapType::key_type>::value,
|
|
"Key types do not match.");
|
|
return map_drop_if(bind_2nd_of_2(is_elem_of<KeyContainer>, keys), map);
|
|
}
|
|
|
|
// API search type: map_keep_if_value : ((val -> Bool), Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Filters the map by values.
|
|
// map_keep_if_value(is_upper_case, {1: a, 2: b, 3: A, 4: C}) == {3: A, 4: C}
|
|
// Also known as filter_values.
|
|
template <typename MapType, typename Pred>
|
|
MapType map_keep_if_value(Pred pred, const MapType& map)
|
|
{
|
|
MapType result;
|
|
for (const auto& key_and_value : map)
|
|
{
|
|
if (internal::invoke(pred, key_and_value.second))
|
|
{
|
|
result.insert(key_and_value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// API search type: map_drop_if_value : ((value -> Bool), Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Filters the map by values.
|
|
// map_drop_if_value(is_lower_case, {1: a, 2: b, 3: A, 4: C}) == {3: A, 4: C}
|
|
// Inverse of map_keep_if_value.
|
|
template <typename MapType, typename Pred>
|
|
MapType map_drop_if_value(Pred pred, const MapType& map)
|
|
{
|
|
return map_keep_if_value(logical_not(pred), map);
|
|
}
|
|
|
|
// API search type: map_keep_values : ([value], Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Keeps only the pairs of the map found in the value list.
|
|
// map_keep_values([1, 4], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
|
|
// map_keep_values([1, 5, 6], {a: 1, b: 2, c: 3, d: 4}) == {a: 1}
|
|
template <typename MapType, typename ValueContainer>
|
|
MapType map_keep_values(const ValueContainer& values, const MapType& map)
|
|
{
|
|
static_assert(std::is_same<
|
|
typename ValueContainer::value_type,
|
|
typename MapType::mapped_type>::value,
|
|
"Value types do not match.");
|
|
return map_keep_if_value(
|
|
bind_2nd_of_2(is_elem_of<ValueContainer>, values), map);
|
|
}
|
|
|
|
// API search type: map_drop_values : ([value], Map key val) -> Map key val
|
|
// fwd bind count: 1
|
|
// Keeps only the pairs of the map not found in the value list.
|
|
// Inverse of map_keep_values.
|
|
// map_drop_values([2, 3], {a: 1, b: 2, c: 3, d: 4}) == {a: 1, d: 4}
|
|
template <typename MapType, typename ValueContainer>
|
|
MapType map_drop_values(const ValueContainer& values, const MapType& map)
|
|
{
|
|
static_assert(std::is_same<
|
|
typename ValueContainer::value_type,
|
|
typename MapType::mapped_type>::value,
|
|
"Value types do not match.");
|
|
return map_drop_if_value(
|
|
bind_2nd_of_2(is_elem_of<ValueContainer>, values), map);
|
|
}
|
|
|
|
// API search type: map_pluck : (key, [Map key val]) -> [val]
|
|
// fwd bind count: 1
|
|
// Extracts values to a specific key from a list of maps.
|
|
// map_pluck('a', [{a: 1, b: 2}, {a: 3}, {c: 4}]) == [Just 1, Just 3, Nothing]
|
|
template <typename MapContainer,
|
|
typename ContainerOut =
|
|
std::vector<maybe<typename MapContainer::value_type::mapped_type>>,
|
|
typename MapType = typename MapContainer::value_type,
|
|
typename Key = typename MapType::key_type,
|
|
typename Val = typename MapType::mapped_type>
|
|
ContainerOut map_pluck(const Key& key, const MapContainer& maps)
|
|
{
|
|
return transform_convert<ContainerOut>(
|
|
bind_2nd_of_2(get_from_map<MapType>, key), maps);
|
|
}
|
|
|
|
// API search type: choose : ([(a, b)], a) -> Maybe b
|
|
// fwd bind count: 1
|
|
// Selects a value assigned to a key iff the key exists exactly once.
|
|
// choose([(1,a), (2,b)], 2) == Just b;
|
|
// choose([(1,a), (1,b)], 2) == Nothing;
|
|
// choose([(1,a), (2,b)], 3) == Nothing;
|
|
template<typename Key, typename Val>
|
|
maybe<Val> choose(const std::vector<std::pair<Key, Val>>& pairs, const Key& x)
|
|
{
|
|
if (count(x, transform(fst<Key, Val>, pairs)) != 1)
|
|
return {};
|
|
return get_from_map(pairs_to_map<std::unordered_map<Key, Val>>(pairs), x);
|
|
}
|
|
|
|
// API search type: choose_by : ([((a -> Bool), b)], a) -> Maybe b
|
|
// fwd bind count: 2
|
|
// Iff exactly one predicate is fulfilled
|
|
// the value assigned to this predicate is selected.
|
|
// choose_by([(is_even,a), (is_bigger_than_3,b)], 2) == Just a;
|
|
// choose_by([(is_even,a), (is_bigger_than_3,b)], 5) == Just b;
|
|
// choose_by([(is_even,a), (is_bigger_than_3,b)], 1) == Nothing;
|
|
// choose_by([(is_even,a), (is_bigger_than_3,b)], 4) == Nothing;
|
|
template<typename Key, typename Val>
|
|
maybe<Val> choose_by(
|
|
const std::vector<std::pair<std::function<bool(const Key&)>, Val>>& pairs,
|
|
const Key& x)
|
|
{
|
|
maybe<Val> result;
|
|
for (const auto& p : pairs)
|
|
{
|
|
if (internal::invoke(p.first, x))
|
|
{
|
|
if (is_just(result))
|
|
{
|
|
return nothing<Val>();
|
|
}
|
|
result = p.second;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// API search type: choose_lazy : ([(a, (() -> b))], a) -> Maybe b
|
|
// fwd bind count: 1
|
|
// Evaluates a lazy value assigned to a key iff the key exists exactly once.
|
|
// choose_lazy([(1,a), (2,b)], 2) == Just b();
|
|
// choose_lazy([(1,a), (1,b)], 2) == Nothing;
|
|
// choose_lazy([(1,a), (2,b)], 3) == Nothing;
|
|
template <typename Key, typename ValStub>
|
|
auto choose_lazy(const std::vector<std::pair<Key, ValStub>>& pairs,
|
|
const Key& x)
|
|
{
|
|
using Ret = maybe<std::decay_t<internal::invoke_result_t<ValStub>>>;
|
|
const auto res = choose(pairs, x);
|
|
if (res.is_nothing())
|
|
return Ret{};
|
|
else
|
|
return Ret{res.unsafe_get_just()()};
|
|
}
|
|
|
|
// API search type: choose_by_lazy : ([((a -> Bool), (() -> b))], a) -> Maybe b
|
|
// fwd bind count: 2
|
|
// Iff exactly one predicate is fulfilled
|
|
// the lazy value assigned to this predicate is evaluated.
|
|
// choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 2) == Just a();
|
|
// choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 5) == Just b();
|
|
// choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 1) == Nothing;
|
|
// choose_by_lazy([(is_even,a), (is_bigger_than_3,b)], 4) == Nothing;
|
|
template <typename Key, typename ValStub>
|
|
auto choose_by_lazy(
|
|
const std::vector<std::pair<std::function<bool(const Key&)>, ValStub>>& pairs,
|
|
const Key& x)
|
|
{
|
|
using Ret = maybe<std::decay_t<internal::invoke_result_t<ValStub>>>;
|
|
|
|
const auto res = choose_by(pairs, x);
|
|
if (res.is_nothing())
|
|
return Ret{};
|
|
else
|
|
return Ret{res.unsafe_get_just()()};
|
|
}
|
|
|
|
// API search type: choose_def : (b, [(a, b)], a) -> b
|
|
// fwd bind count: 1
|
|
// Selects a value assigned to a key iff the key exists exactly once,
|
|
// otherwise returns the given default value.
|
|
// choose_def(c, [(1,a), (2,b)], 2) == b;
|
|
// choose_def(c, [(1,a), (1,b)], 2) == c;
|
|
// choose_def(c, [(1,a), (2,b)], 3) == c;
|
|
template<typename Key, typename Val>
|
|
Val choose_def(const Val& def,
|
|
const std::vector<std::pair<Key, Val>>& pairs, const Key& x)
|
|
{
|
|
if (count(x, transform(fst<Key, Val>, pairs)) != 1)
|
|
return def;
|
|
return get_from_map_with_def(
|
|
pairs_to_map<std::unordered_map<Key, Val>>(pairs), def, x);
|
|
}
|
|
|
|
// API search type: choose_by_def : (b, [((a -> Bool), b)], a) -> b
|
|
// fwd bind count: 2
|
|
// Iff exactly one predicate is fulfilled
|
|
// the value assigned to this predicate is selected.
|
|
// Otherwise the given default value is returned.
|
|
// choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 2) == Just a;
|
|
// choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 5) == Just b;
|
|
// choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 1) == c;
|
|
// choose_by_def(c, [(is_even,a), (is_bigger_than_3,b)], 4) == c;
|
|
template<typename Key, typename Val>
|
|
Val choose_by_def(const Val& def,
|
|
const std::vector<std::pair<std::function<bool(const Key&)>, Val>>& pairs,
|
|
const Key& x)
|
|
{
|
|
return just_with_default(def, choose_by(pairs, x));
|
|
}
|
|
|
|
// API search type: choose_def_lazy : ((() -> b), [(a, (() -> b))], a) -> b
|
|
// fwd bind count: 1
|
|
// Evaluates a lazy value assigned to a key iff the key exists exactly once,
|
|
// otherwise evaluates the given default lazy value.
|
|
// choose_def_lazy(c, [(1,a), (2,b)], 2) == b();
|
|
// choose_def_lazy(c, [(1,a), (1,b)], 2) == c();
|
|
// choose_def_lazy(c, [(1,a), (2,b)], 3) == c();
|
|
template <typename Key, typename ValStub>
|
|
auto choose_def_lazy(const ValStub& def,
|
|
const std::vector<std::pair<Key, ValStub>>& pairs,
|
|
const Key& x)
|
|
{
|
|
return choose_def(def, pairs, x)();
|
|
}
|
|
|
|
// API search type: choose_by_def_lazy : ((() -> b), [((a -> Bool), (() -> b))], a) -> b
|
|
// fwd bind count: 2
|
|
// Iff exactly one predicate is fulfilled
|
|
// the value assigned to this predicate is evaluated.
|
|
// Otherwise the given default value is evaluated and returned.
|
|
// choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 2) == Just a();
|
|
// choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 5) == Just b();
|
|
// choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 1) == c();
|
|
// choose_by_def_lazy(c, [(is_even,a), (is_bigger_than_3,b)], 4) == c();
|
|
template <typename Key, typename ValStub>
|
|
auto choose_by_def_lazy(
|
|
const ValStub& def,
|
|
const std::vector<std::pair<std::function<bool(const Key&)>, ValStub>>& pairs,
|
|
const Key& x)
|
|
{
|
|
return choose_by_def(def, pairs, x)();
|
|
}
|
|
|
|
} // namespace fplus
|