Permutations!
This commit is contained in:
parent
45a3710626
commit
946d4b96b1
11
examples/permutations.mq
Normal file
11
examples/permutations.mq
Normal 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
|
||||
];
|
@ -362,6 +362,29 @@ Interpreter::Interpreter()
|
||||
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> {
|
||||
Chord chord;
|
||||
Try(create_chord(chord.notes, i, std::move(args)));
|
||||
|
@ -89,7 +89,7 @@ struct Runner
|
||||
}
|
||||
|
||||
/// 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));
|
||||
|
||||
@ -97,7 +97,7 @@ struct Runner
|
||||
dump(ast);
|
||||
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;
|
||||
}
|
||||
return {};
|
||||
@ -185,6 +185,7 @@ static Result<void> Main(std::span<char const*> args)
|
||||
}
|
||||
|
||||
if (runnables.empty() || enable_repl) {
|
||||
enable_repl = true;
|
||||
for (;;) {
|
||||
char *input_buffer = readline("> ");
|
||||
if (input_buffer == nullptr) {
|
||||
@ -215,7 +216,7 @@ static Result<void> Main(std::span<char const*> args)
|
||||
continue;
|
||||
}
|
||||
|
||||
auto result = runner.run(raw, "<repl>");
|
||||
auto result = runner.run(raw, "<repl>", true);
|
||||
if (not result.has_value()) {
|
||||
std::cout << std::flush;
|
||||
std::cerr << result.error() << std::flush;
|
||||
|
@ -667,6 +667,8 @@ struct Note
|
||||
|
||||
bool operator==(Note const&) const;
|
||||
|
||||
std::partial_ordering operator<=>(Note const&) const;
|
||||
|
||||
/// Simplify note by adding base to octave if octave is present
|
||||
void simplify_inplace();
|
||||
};
|
||||
@ -714,7 +716,6 @@ struct Value
|
||||
/// Using Explicit_Bool to prevent from implicit casts
|
||||
static Value from(Explicit_Bool b);
|
||||
|
||||
|
||||
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_view s); ///< Create value of type symbol holding provided symbol
|
||||
@ -777,6 +778,8 @@ struct Value
|
||||
usize size() const;
|
||||
|
||||
bool operator==(Value const& other) const;
|
||||
|
||||
std::partial_ordering operator<=>(Value const& other) const;
|
||||
};
|
||||
|
||||
template<Value::Type>
|
||||
|
49
src/value.cc
49
src/value.cc
@ -249,6 +249,44 @@ usize Value::size() const
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
note.simplify_inplace();
|
||||
@ -401,7 +449,6 @@ std::ostream& operator<<(std::ostream& os, Note note)
|
||||
if (note.length) {
|
||||
os << ":len=" << *note.length;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user