Comments (20)
round
would be a builtin. The question is more how that builtin is referenced within Murex. Take the Fish code you've got:
math -s2 "$pinact * 4096 / 1073741824"
here the expression is a string passed to math
(it is quoted). Whereas in Murex, expressions do not need to be quoted. so the same code could read (ignoring the -s2
arg for now):
$pinact * 4096 / 1073741824
But this means if we want to inject commands, be they functions, builtins or external commands, into an expression, you need to invoke a sub-shell: ${ ... }
. This might be less of an issue here because you're rounding the output of the expression, so the code would be:
round ${$pinact * 4096 / 1073741824} 2 -> set pinact
I'm just thinking a few steps ahead about how to interpolate expressions and statements (more traditional command line arguments) more elegantly since if I'm adding round
, I could add a bunch more math functions as builtins too.
from murex.
Builtins are commands but that’s true for all shells. The way “round” works in fish is that it’s a function of the math
builtin. Fish doesn’t support expressions natively like Murex, so all Fish expressions need to be prefixed with math
. And thus anything that follows are parameters to the math
builtin, “round” and all.
Murex used to operate this way too but it can lead to some pretty counterintuitive syntax if your expressions include strings (specifically about quoting and escaping). Which is why expressions can now be “naked” in Murex. But the problem with naked expressions is having a parser that is smart enough to know what a command line is a command and parameters (ie statement) and when it is an expression. Because the two would have fundamentally different rules for parsing and execution.
from murex.
The problem with C notation is that you then have two ways of writing a command:
cat file1.txt file2.txt
cat("file1.txt", "file2.txt")
I think this could get very confusing.
Whereas with the LISPy notation, you would only have one way of writing a command:
cat file1.txt file2.txt
You can then use that in expressions or statements:
cat file1.txt file2.txt -> set value
value = (cat file1.txt file2.txt)
The problem only really arises if you want to start nesting heavily. But that shouldn't be needed often because Murex uses curly braces for code blocks:
if { conditional } then { result }
I guess you could probably argue that the embedded expression should be a curly brace as well though. But that's basically how the shell already currently works:
value = ${cat file1.txt file2.txt}
I think I might need to park this thought and just write the round
builtin because I'm going round in circles and as a result haven't written any new code in a week.
from murex.
I also believe it needs time to mature.
and probably other opinions
The problem with C notation is that you then have two ways of writing a command:
cat file1.txt file2.txt
cat("file1.txt", "file2.txt")
good point
Thinking shell and not C notation, the below looks relatively intuitive to me:
value = ${round (1+1) (-5/2)}
from murex.
Going back to the round
builtin. I have a design for what that builtin should look like:
round [--ceil | --floor] <precision> <value>
--up
will round up--down
will round down (default)
- If this is an integer, then it will round to the nearest (up or down depending on flag) multiple of that integer. That integer can be 10, 100, or even odd numbers like 3 or 77.
- If this is a float (eg 0.001) then it will round to the nearest decimal place specified. When floats are used, it just rounds to that many decimal places. It doesn't try to do anything clever with multiples like with integers. I'm tempted to even say the above flags aren't allowed with floats.
This incorporates a few different rounding mechanics in a (hopefully) intuitive way.
from murex.
@orefalo I've been having a think about this. From what I recall, Fish does this via the math
builtin (https://fishshell.com/docs/current/cmds/math.html). Whereas expressions in Murex are first class citizens. So the following is valid command line:
5 / 4
No math
, expr
, let
, $(( .. ))
, nor any other special syntax needed to do math.
This could make it a little counterintuitive having special functions for expressions. However the reverse of inlining shell commands into an expression might be a little ugly
value = ${round ${5/4} 2}
So I wonder if there is scope here to expand on the expression parser and have something like command()
as syntactic sugar for ${command}
. Thus the above expression would read as:
value = round(5/4, 2)
This would also allow for any command to be called as an expression. eg
value = cat("filename")
The drawback of this is it effectively creates two programming languages:
- functional, pipe-driven that is heavy on barewords (like Bash, Fish, etc)
- expression-driven, like C etc
...where both can co-exist in the same source file. While the expressiveness of this appeals to me, it does also feel a little schizophrenic and likely very confusing to anyone new to the shell.
What's your thoughts?
from murex.
That is correct,
For reference, that's a sample line of code I use today in my script set pinact (math -s2 "$pinact * 4096 / 1073741824")
The project is here, https://github.com/orefalo/free, it's a mimic of the Linux free
command for osx.
I understand your comments, but... honestly... I have a hard time foreseeing the implication of such decision.
5min later:
other than maybe confusing the script authors as to what is an internal routine vs a sub program.
I personally have a preference for internal routines because they are portable and faster.
so running code like this:
set vmstat (vm_stat | string match -r "[0-9]+")
set appmem (math -s2 "$panon - $ppurge")
printf 'Mem: %6.2fGb %6.2fGb %6.2fGb %6.2fGb %6.2fGb %6.2fGb\n' $total_mem $used $free $panon $pwired $pcomp
will run on any fish shell, no matter the platform.
if I had to replace the rounding with a call to the round command - I would loose portability. (which I agree for this particular free script is not so important)
Sounds like a choice of implementation: providing a rich set of commands or delegating to sub commands.
fish started slim and over time grew more and more useful internal routines especially around math, formatting, text manipulation.
from murex.
@Pascalio you've had some really good input into the language design of this shell. What's your thoughts on this?
from murex.
I am still scratching my head about your answer above.
regardless... functionally speaking, round
plays at the same level and rand
https://murex.rocks/docs/commands/rand.html
and therefore it should be implemented with the same concepts.
actually... let me try!
round precision:int value:int|float
typical usage:
rand float -> round 2
round 2 3.1416230492
pinact = round 2 $pinact * 4096 / 1073741824
from murex.
That last example would look like:
pinact = ${round 2 ${$pinact * 4096 / 1073741824} }
So the question is whether we want a little syntactical sugar in the parser to make expressions less ugly.
You're right it doesn't impact the implementation of round
as a builtin though. It would be an update to the Murex parser to make usage of round
more convenient.
from murex.
Now I get the point... indeed a good point.
beyond the ugliness... it's really about how intuitive the expression syntax is.
In that regard, and speaking about my own journey -> I would have never figured this line
pinact = ${round 2 ${$pinact * 4096 / 1073741824} }
that's because mentally, I see ${} to run commands, not builtins. This might trick a few users
now.. what would the optimized syntax
look like?
ideally it should be pinact = round 2 $pinact * 4096 / 1073741824
Next would be.. what the implication of such decision to the rest of the shell syntax?
from murex.
To illustrate my point, take a look at the following screenshot. Nearly all the commands on there fail.
- you cannot have naked expressions, they're all just parameters of
math
builtin - you cannot have unquoted multiplication because
*
is treated as a wildcard. - "round" isn't a builtin (
type
isn't aware of it, and it cannot be ran withoutmath
)
This behaviour is in line with what's in Fish's docs: https://fishshell.com/docs/current/cmds/math.html
There math
is the command and all the functions in there are really just facets of yet another language (ie math
) inside Fish's language. In essence, using functions in math
isn't really any different to calling awk
or sed
functions from Fish.
Whereas with Murex, you have naked expressions. So the following is valid command lines:
5 * 5
# returns 25
^ this expression doesn't need to be prefixed with math
. It doesn't need to be quoted as a string because Murex is smart enough to spot that *
is being used as a mathematical operator rather than a wildcard.
now.. what would the
optimized syntax
look like?
ideally it should bepinact = round 2 $pinact * 4096 / 1073741824
Next would be.. what the implication of such decision to the rest of the shell syntax?
Unfortunately that syntax wouldn't work because you're not defining your order of operations.
Take the following equation for example: 3 + 3 * 2
If you read the answer left to right you get 12
. Except that's not how equations work, the actual answer should be 9
.
If you want 12
then the equation should be (3 + 3) * 2
-- the brackets are calculated first, giving you 6 * 2
.
So if we had an equation that looked like value = round 1+1 -5/2
(I've adjusted whitespace to make it clear what the intended grouping for parameters should be)
Here we are intending round( 2, -2.5 )
but how does the parser know it's that and not the equation 1 + 1 - 5 / 2
? Things get even more tricky if you want to perform multiple functions within an equation.
This is why C-style languages have the function(parameter, parameter)
syntax, it makes it very easy it mix functions with equations.
So whatever syntax we use for embedding functions within expressions in Murex, it would need to do a couple of things:
- signify the start and end of the function (like with parentheses in C-derived languages)
- it would need to use a non-whitespace character to delimit between parameters (like comma is used in C-derived languages).
Another thought I had was maybe borrowing from LISP:
pinact = (round 2, $pinact * 4096 / 1073741824)
I can't say I love that personally but at least it is more readable that ${ ... }
everywhere.
A third option would be to use another sigil (like how $
is a scalar, @
is an array, %
is an object generator). We could use &
for functions:
pinact = &round(2, $pinact * 4096 / 1073741824)
The advantage of this is that you could then use the same syntax in statements as well. eg
out: The rounded answer is &round(2, $pinact * 4096 / 1073741824)
But I think this would splinter the language too much plus there's already lots of sigils in Murex, I'm not convinsed introducing yet another one is a smart idea.
Unfortunately any solution I think of would be quiet a departure from your typical shell syntax.
from murex.
thank you so much for all the details - this is very nice to take so much time
back in the time (13 years ago!), I wrote an arithmetic expression solver with arithmetic priority
https://github.com/orefalo/ExpressionEvaluator
the fact that we are discussing this topic today makes me wonder "It took time, but it was meant to be..." ;-)
Why not using parenthesis to solve this priority issue?
or even better, implement arithmetic priority and extend it to built ins?
so you would have this order + - / * %.. the builtins
again, () could be use to force priority evaluation
-> I personally believe it's an overkill at this point.
with (), the following should do
pinact = round 2 ($pinact * 4096 / 1073741824)
and with priority, the following should work just fine
pinact = round 2 $pinact * 4096 / 1073741824
from murex.
Why not using parenthesis to solve this priority issue?
That was my point :)
or even better, implement arithmetic priority and extend it to built ins?
Murex already has that. I guess the issue is more around the grouping of parameters rather than order of operations. eg take the follow:
value = round 1 + 1 -5 / 2
since whitespace isn't a delimiter, how does the parser know which values and operators belong to which parameter of round?
Parenthesis solve this for functions that take one parameter but then we would need another delimiter for multi-parameter functions, or another set of parenthesis if we were to go "fully LISP". eg
# BASH-like
value = ${round ${1+1} ${-5/2}}
# LISP-like
value = (round (1+1) (-5/2))
# C-like
value = round(1+1, -5/2)
# Something new?
value = (round: 1+1, -5/2)
though the more I think about it, the less i like the idea of this. It fragments the language and as a result creates a number of non-obvious edge cases. eg should round 1+1 -5/2
be a valid command (like cat filename
)? And if so, you have the whole grouping problem all over again. Meaning you'd have to write round (1+1) (-5/2)
. In which case we're back to the LISPy syntax of value = (round (1+1) (-5/2))
.
Alternatively, the same ugly command could be refactored to something more readable using variables:
places = 1+1; float = -5/2
value = ${round $places $float}
....a lot to think about....
from murex.
Thinking a little more, advantage of a LISPy syntax is that ()
is already a special case string. so it wouldn't take much additional code to first parse that as an expression and if it's not a valid expression, then parse it as a string. Thus bringing the syntax of expressions and statements a bit more in sync
from murex.
since whitespace isn't a delimiter, how does the parser know which values and operators belong to which parameter of round?
good point
It fragments the language
agreed
value = ${round ${1+1} ${-5/2}}
value = (round (1+1) (-5/2))
value = round(1+1, -5/2)
value = (round: 1+1, -5/2)
I am shared between the Lisp and C like versions - yet with a preference on C.
With the list notation, we already have a playbook - https://michaelnotebook.com/notes/parentheses/index.html#:~:text=They%20mean%20that%20there%20needs,a%20level%20of%20the%20tree%22.
The C notation, gets you closer to a functional language.
thinking twice I prefer this notation - as it comes natural for anyone who did C,C++, Java, JS..etc
from murex.
@orefalo I've written a first pass of the round
builtin (now in develop
)
from murex.
thank you Laurence..
and I am writing this for you https://orefalo.github.io/murex-docs/
still a WIP
https://github.com/orefalo/murex-docs
from murex.
wow that looks good. Thank you :)
from murex.
merged round
into 4.4 release
from murex.
Related Issues (20)
- broken links on landing page HOT 2
- ':>' operator HOT 1
- Cursor flickering on backspace while having tab completion active on some terminal emulators HOT 10
- Ternary operator
- lambda support
- Create a "deprecated" section
- Autocomplete to suggest values after flags have been added HOT 3
- Disable walk history while in `[f9]` preview mode
- readline: some hotkeys no longer update terminal with readline state
- Variables sometimes return base64 encoded values
- Error on windows: Error creating table preview_command: Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work HOT 9
- Website: Opening "config" builtins page from left menu breaks site HOT 2
- "Nullness" of a JSON null is lost while iterating using formap HOT 4
- rewrite object creator parser
- Zero-length environment variables reported as null HOT 1
- Murex bug: database is locked (5) (SQLITE_BUSY): '/home/me/.murex_modules/cache.db' HOT 1
- murex panic: runtime error: index out of range [0] with length 0 HOT 2
- Comparision to NuShell HOT 1
- bg { command } fails to run command HOT 4
- expressions/exp14 causes panic: `index out of range`
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from murex.