Algorithms like min don't flatten all the way

To restore previous behaviour one can use `min (flat x)`
This commit is contained in:
Robert Bendun 2022-09-05 22:30:11 +02:00
parent eb822a4a6e
commit ab0ba8d4c8
3 changed files with 65 additions and 31 deletions

View File

@ -833,14 +833,15 @@ struct Value
/// Using Explicit_Bool to prevent from implicit casts /// Using Explicit_Bool to prevent from implicit casts
static Value from(Explicit_Bool b); static Value from(Explicit_Bool b);
static Value from(Number n); ///< Create value of type number holding provided number static Value from(Array &&array); ///< Create value of type array holding provided array
static Value from(std::string s); ///< Create value of type symbol holding provided symbol static Value from(Block &&l); ///< Create value of type block holding provided block
static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol static Value from(Chord chord); ///< Create value of type music holding provided chord
static Value from(char const* s); ///< Create value of type symbol holding provided symbol static Value from(Note n); ///< Create value of type music holding provided note
static Value from(Block &&l); ///< Create value of type block holding provided block static Value from(Number n); ///< Create value of type number holding provided number
static Value from(Array &&array); ///< Create value of type array holding provided array static Value from(char const* s); ///< Create value of type symbol holding provided symbol
static Value from(Note n); ///< Create value of type music holding provided note static Value from(std::string s); ///< Create value of type symbol holding provided symbol
static Value from(Chord chord); ///< Create value of type music holding provided chord static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol
static Value from(std::vector<Value> &&array); ///< Create value of type array holding provided array
enum class Type enum class Type
{ {
@ -1094,4 +1095,8 @@ static constexpr bool is_callable(Value::Type type)
return type == Value::Type::Block || type == Value::Type::Intrinsic; return type == Value::Type::Block || type == Value::Type::Intrinsic;
} }
/// Flattens one layer: `[[[1], 2], 3]` becomes `[[1], 2, 3]`
Result<std::vector<Value>> flatten(Interpreter &i, std::span<Value>);
Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value>);
#endif #endif

View File

@ -111,6 +111,7 @@ static Result<Array> into_flat_array(Interpreter &i, std::vector<Value> args)
return into_flat_array(i, std::span(args)); return into_flat_array(i, std::span(args));
} }
/// Helper to convert method to it's name /// Helper to convert method to it's name
template<auto> struct Number_Method_Name; template<auto> struct Number_Method_Name;
template<> struct Number_Method_Name<&Number::floor> { static constexpr auto value = "floor"; }; template<> struct Number_Method_Name<&Number::floor> { static constexpr auto value = "floor"; };
@ -466,8 +467,8 @@ static Result<Value> builtin_update(Interpreter &i, std::vector<Value> args)
if (Lazy_And_Number::typecheck_front(args)) { if (Lazy_And_Number::typecheck_front(args)) {
auto [v, index] = Lazy_And_Number::move_from(args); auto [v, index] = Lazy_And_Number::move_from(args);
auto array = Try(into_flat_array(i, { Value::from(std::move(v)) })); auto array = Try(flatten(i, { Value::from(std::move(v)) }));
array.elements[index.as_int()] = std::move(args.back()); array[index.as_int()] = std::move(args.back());
return Value::from(std::move(array)); return Value::from(std::move(array));
} }
@ -500,41 +501,41 @@ static Result<Value> builtin_flat(Interpreter &i, std::vector<Value> args)
static Result<Value> builtin_shuffle(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_shuffle(Interpreter &i, std::vector<Value> args)
{ {
static std::mt19937 rnd{std::random_device{}()}; static std::mt19937 rnd{std::random_device{}()};
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
std::shuffle(array.elements.begin(), array.elements.end(), rnd); std::shuffle(array.begin(), array.end(), rnd);
return Value::from(std::move(array)); return Value::from(std::move(array));
} }
/// Permute arguments /// Permute arguments
static Result<Value> builtin_permute(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_permute(Interpreter &i, std::vector<Value> args)
{ {
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
std::next_permutation(array.elements.begin(), array.elements.end()); std::next_permutation(array.begin(), array.end());
return Value::from(std::move(array)); return Value::from(std::move(array));
} }
/// Sort arguments /// Sort arguments
static Result<Value> builtin_sort(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_sort(Interpreter &i, std::vector<Value> args)
{ {
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
std::sort(array.elements.begin(), array.elements.end()); std::sort(array.begin(), array.end());
return Value::from(std::move(array)); return Value::from(std::move(array));
} }
/// Reverse arguments /// Reverse arguments
static Result<Value> builtin_reverse(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_reverse(Interpreter &i, std::vector<Value> args)
{ {
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
std::reverse(array.elements.begin(), array.elements.end()); std::reverse(array.begin(), array.end());
return Value::from(std::move(array)); return Value::from(std::move(array));
} }
/// Get minimum of arguments /// Get minimum of arguments
static Result<Value> builtin_min(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_min(Interpreter &i, std::vector<Value> args)
{ {
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
auto min = std::min_element(array.elements.begin(), array.elements.end()); auto min = std::min_element(array.begin(), array.end());
if (min == array.elements.end()) if (min == array.end())
return Value{}; return Value{};
return *min; return *min;
} }
@ -542,9 +543,9 @@ static Result<Value> builtin_min(Interpreter &i, std::vector<Value> args)
/// Get maximum of arguments /// Get maximum of arguments
static Result<Value> builtin_max(Interpreter &i, std::vector<Value> args) static Result<Value> builtin_max(Interpreter &i, std::vector<Value> args)
{ {
auto array = Try(into_flat_array(i, std::move(args))); auto array = Try(flatten(i, std::move(args)));
auto max = std::max_element(array.elements.begin(), array.elements.end()); auto max = std::max_element(array.begin(), array.end());
if (max == array.elements.end()) if (max == array.end())
return Value{}; return Value{};
return *max; return *max;
} }
@ -563,10 +564,10 @@ static Result<Value> builtin_partition(Interpreter &i, std::vector<Value> args)
auto predicate = std::move(args.front()); auto predicate = std::move(args.front());
Try(guard(is_callable, predicate)); Try(guard(is_callable, predicate));
auto array = Try(into_flat_array(i, std::span(args).subspan(1))); auto array = Try(flatten(i, std::span(args).subspan(1)));
Array tuple[2] = {}; Array tuple[2] = {};
for (auto &value : array.elements) { for (auto &value : array) {
tuple[Try(predicate(i, { std::move(value) })).truthy()].elements.push_back(std::move(value)); tuple[Try(predicate(i, { std::move(value) })).truthy()].elements.push_back(std::move(value));
} }
@ -589,13 +590,13 @@ static Result<Value> builtin_rotate(Interpreter &i, std::vector<Value> args)
} }
auto offset = std::move(args.front()).n.as_int(); auto offset = std::move(args.front()).n.as_int();
auto array = Try(into_flat_array(i, std::span(args).subspan(1))); auto array = Try(flatten(i, std::span(args).subspan(1)));
if (offset > 0) { if (offset > 0) {
offset = offset % array.elements.size(); offset = offset % array.size();
std::rotate(array.elements.begin(), array.elements.begin() + offset, array.elements.end()); std::rotate(array.begin(), array.begin() + offset, array.end());
} else if (offset < 0) { } else if (offset < 0) {
offset = -offset % array.elements.size(); offset = -offset % array.size();
std::rotate(array.elements.rbegin(), array.elements.rbegin() + offset, array.elements.rend()); std::rotate(array.rbegin(), array.rbegin() + offset, array.rend());
} }
return Value::from(std::move(array)); return Value::from(std::move(array));
} }

View File

@ -130,6 +130,14 @@ Value Value::from(Array &&array)
return v; return v;
} }
Value Value::from(std::vector<Value> &&array)
{
Value v;
v.type = Type::Array;
v.array = Array { .elements = std::move(array) };
return v;
}
Value Value::from(Note n) Value Value::from(Note n)
{ {
Value v; Value v;
@ -494,3 +502,23 @@ std::ostream& operator<<(std::ostream& os, Chord const& chord)
} }
return os << ']'; return os << ']';
} }
Result<std::vector<Value>> flatten(Interpreter &interpreter, std::span<Value> args)
{
std::vector<Value> result;
for (auto &x : args) {
if (is_indexable(x.type)) {
for (usize i = 0; i < x.size(); ++i) {
result.push_back(Try(x.index(interpreter, i)));
}
} else {
result.push_back(std::move(x));
}
}
return result;
}
Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value> args)
{
return flatten(i, std::span(args));
}