Permutations!

This commit is contained in:
Robert Bendun 2022-06-02 23:17:02 +02:00
parent 45a3710626
commit 946d4b96b1
5 changed files with 90 additions and 5 deletions

11
examples/permutations.mq Normal file
View File

@ -0,0 +1,11 @@
var factorial = [n | if (n < 2) [1] [factorial (n-1) * n]];
var for_all_permutations = [array fun |
var iter = [start stop x | if (start >= stop) [x] [iter (start+1) stop (fun x)]];
iter 0 (factorial (len array)) array
];
for_all_permutations (flat 1 2 3 4 5) [array|
say array;
permute array
];

View File

@ -362,6 +362,29 @@ Interpreter::Interpreter()
return Value::from(std::move(array)); return Value::from(std::move(array));
}); });
global.force_define("permute", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
Array array;
for (auto &arg : args) {
switch (arg.type) {
case Value::Type::Array:
std::move(arg.array.elements.begin(), arg.array.elements.end(), std::back_inserter(array.elements));
break;
case Value::Type::Block:
for (auto j = 0u; j < arg.blk.size(); ++j) {
array.elements.push_back(Try(arg.blk.index(i, j)));
}
break;
default:
array.elements.push_back(std::move(arg));
}
}
std::next_permutation(array.elements.begin(), array.elements.end());
return Value::from(std::move(array));
});
global.force_define("chord", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> { global.force_define("chord", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
Chord chord; Chord chord;
Try(create_chord(chord.notes, i, std::move(args))); Try(create_chord(chord.notes, i, std::move(args)));

View File

@ -89,7 +89,7 @@ struct Runner
} }
/// Run given source /// Run given source
Result<void> run(std::string_view source, std::string_view filename) Result<void> run(std::string_view source, std::string_view filename, bool output = false)
{ {
auto ast = Try(Parser::parse(source, filename)); auto ast = Try(Parser::parse(source, filename));
@ -97,7 +97,7 @@ struct Runner
dump(ast); dump(ast);
return {}; return {};
} }
if (auto result = Try(interpreter.eval(std::move(ast))); result.type != Value::Type::Nil) { if (auto result = Try(interpreter.eval(std::move(ast))); output && result.type != Value::Type::Nil) {
std::cout << result << std::endl; std::cout << result << std::endl;
} }
return {}; return {};
@ -185,6 +185,7 @@ static Result<void> Main(std::span<char const*> args)
} }
if (runnables.empty() || enable_repl) { if (runnables.empty() || enable_repl) {
enable_repl = true;
for (;;) { for (;;) {
char *input_buffer = readline("> "); char *input_buffer = readline("> ");
if (input_buffer == nullptr) { if (input_buffer == nullptr) {
@ -215,7 +216,7 @@ static Result<void> Main(std::span<char const*> args)
continue; continue;
} }
auto result = runner.run(raw, "<repl>"); auto result = runner.run(raw, "<repl>", true);
if (not result.has_value()) { if (not result.has_value()) {
std::cout << std::flush; std::cout << std::flush;
std::cerr << result.error() << std::flush; std::cerr << result.error() << std::flush;

View File

@ -667,6 +667,8 @@ struct Note
bool operator==(Note const&) const; bool operator==(Note const&) const;
std::partial_ordering operator<=>(Note const&) const;
/// Simplify note by adding base to octave if octave is present /// Simplify note by adding base to octave if octave is present
void simplify_inplace(); void simplify_inplace();
}; };
@ -714,7 +716,6 @@ 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(Number n); ///< Create value of type number holding provided number
static Value from(std::string s); ///< Create value of type symbol holding provided symbol static Value from(std::string s); ///< Create value of type symbol holding provided symbol
static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol
@ -777,6 +778,8 @@ struct Value
usize size() const; usize size() const;
bool operator==(Value const& other) const; bool operator==(Value const& other) const;
std::partial_ordering operator<=>(Value const& other) const;
}; };
template<Value::Type> template<Value::Type>

View File

@ -249,6 +249,44 @@ usize Value::size() const
unreachable(); unreachable();
} }
std::partial_ordering Value::operator<=>(Value const& rhs) const
{
// TODO Block - array comparison should be allowed
if (type != rhs.type) {
return std::partial_ordering::unordered;
}
switch (type) {
case Type::Nil:
return std::partial_ordering::equivalent;
case Type::Bool:
return b <=> rhs.b;
case Type::Symbol:
return s <=> rhs.s;
case Type::Number:
return n <=> rhs.n;
case Type::Array:
return std::lexicographical_compare_three_way(
array.elements.begin(), array.elements.end(),
rhs.array.elements.begin(), rhs.array.elements.end()
);
case Type::Music:
return chord.notes.front() <=> rhs.chord.notes.front();
// Block should be compared but after evaluation so for now it's Type::Block
case Type::Block:
case Type::Intrinsic:
return std::partial_ordering::unordered;
}
unreachable();
}
std::ostream& operator<<(std::ostream& os, Value const& v) std::ostream& operator<<(std::ostream& os, Value const& v)
{ {
switch (v.type) { switch (v.type) {
@ -391,6 +429,16 @@ void Note::simplify_inplace()
} }
} }
std::partial_ordering Note::operator<=>(Note const& rhs) const
{
if (octave.has_value() == rhs.octave.has_value()) {
if (octave.has_value())
return (12 * *octave) + base <=> (12 * *rhs.octave) + rhs.base;
return base <=> rhs.base;
}
return std::partial_ordering::unordered;
}
std::ostream& operator<<(std::ostream& os, Note note) std::ostream& operator<<(std::ostream& os, Note note)
{ {
note.simplify_inplace(); note.simplify_inplace();
@ -401,7 +449,6 @@ std::ostream& operator<<(std::ostream& os, Note note)
if (note.length) { if (note.length) {
os << ":len=" << *note.length; os << ":len=" << *note.length;
} }
return os; return os;
} }