Git Product home page Git Product logo

Comments (20)

lmorg avatar lmorg commented on June 1, 2024 1

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.

lmorg avatar lmorg commented on June 1, 2024 1

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.

lmorg avatar lmorg commented on June 1, 2024 1

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.

orefalo avatar orefalo commented on June 1, 2024 1

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.

lmorg avatar lmorg commented on June 1, 2024 1

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.

lmorg avatar lmorg commented on June 1, 2024

@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:

  1. functional, pipe-driven that is heavy on barewords (like Bash, Fish, etc)
  2. 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.

orefalo avatar orefalo commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

@Pascalio you've had some really good input into the language design of this shell. What's your thoughts on this?

from murex.

orefalo avatar orefalo commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

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.

orefalo avatar orefalo commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

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 without math)
image

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 be pinact = 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:

  1. signify the start and end of the function (like with parentheses in C-derived languages)
  2. 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.

orefalo avatar orefalo commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

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.

orefalo avatar orefalo commented on June 1, 2024

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.

image

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.

lmorg avatar lmorg commented on June 1, 2024

@orefalo I've written a first pass of the round builtin (now in develop)

from murex.

orefalo avatar orefalo commented on June 1, 2024

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.

lmorg avatar lmorg commented on June 1, 2024

wow that looks good. Thank you :)

from murex.

lmorg avatar lmorg commented on June 1, 2024

merged round into 4.4 release

from murex.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.