Live data from Hacker News

When if is just a function

ryelang.org

21–30 of 111 posts

Re: When if is just a function

#21

I wish they showed the `else` syntax, because the traditional ALGOL-style if-then-else statement doesn't look native when shoved into most function call notations, unless you have something pretty interesting around named parameters and expressions delimiters.

See the `either` function further down

  either some-condition { print "was true" } { print "was false" }

Re: When if is just a function

#22
post #10

Earlier quoted context omitted.

I checked in Firefox and Chrome (on Linux) and code samples look OK to me. What browser/OS are you using. Maybe send me a screenshot at janko dot itm at gmail.

Same here. I guess it's an issue with (system) dark theme (you can simulate that in dev tools. Android here, so must be Chrome.

I fixed it thanks! I was able to activate dark more in Firefox on desktop and find problems with CSS.

Re: When if is just a function

#23
post #14

This is interesting, but I'm not convinced it's better than the python it's being compared to. Memorizing and understanding the behavior of functions that perform control flow seems no easier than memorizing and understanding hardcoded syntax/keywords. The additional flexibility of making everything a first-class citizen allows people to write code that is too clever for its own good. I could be wrong but I think the…

> I could be wrong but I think there is a broad consensus that reflection is a Bad Idea.

Reflection may be bad in practice for other reasons/conditions, but the lack of simple/minimal/regular primitive conventions in many languages, makes reflection a basket of baddies.

The code blocks of Rye seem comparable to closures, which is a sensible thing to have. Once all code blocks are closures, there are fewer concepts to wrangle, and functional control makes excellent sense.

Re: When if is just a function

#24
post #9
post #6

Earlier quoted context omitted.

I checked the Rye homepage, and it has "dialects" which allow more familiar math infix notation. In that sense it is very tcl-y, tcl technically being a lisp. Looking at their rather confusing looping mechanisms, they probably could benefit from being a little more tcl-y, since tcl has some of the best looping semantics I've worked with.

Any concrete feedback on looping mechanisms being confusing is appreciated.

Certainly:

I can tell the rye devs like the idea of everything being a function. But in their very first "language basics" section, they introduce assignment not as a function call, but as some kind of magic that happens when you have colons in a name.

So when we get to the "looping" section, it is the first time we have seen a colon-having-name outside the context of assignment:

> loop 3 { ::i , prns i }

And it is explained that the above line of code is "injecting" values for the code block to "pick up".

But right away this begs a number of questions:

* Why the double-colon? I would assume each loop-body-evaluation happens in its own scope, and that we're not creating global variables, so a single colon (:i) should be sufficient, right?

* What are we doing, conceptually? Is the ::i meant to be "a function which when given a value modifies its enclosing scope to include the symbol i" or "an unassigned symbol which the loop function will use to do something akin to term-rewriting with?"

* Do we really need a symbol at all, or could we just have a the point-free loop "loop 3 {prns}"?

* If we can't have the point free thing, is it because somehow the injected value would end up "to the left" of prns, if so, why would we want that?

* If we're doing something more like term rewriting, why isn't the symbol given as a separate argument from the body?

Re: When if is just a function

#26
post #5
post #2

Seems lispy

BTW: In Lisps, if is still a special form / macro, because in Lisp lists are evaluated by default, in Rebols if can be a function because blocks (lists) aren't evaluated by default.

You can rarely successfully generalize about languages in the Lisp family. :)

TXR Lisp: (relevant to this article) there is an iff function that takes functional arguments.

Square the odd values in 0 to 9:

  1> (mapcar [iff oddp square use] 0..10)
  (0 1 2 9 4 25 6 49 8 81)
The use function is a synonym of identity: i.e. just use the incoming value as-is

Square the even ones instead by inverting oddp with notf:

  2> (mapcar [iff [notf oddp] square use] 0..10)
  (0 1 4 3 16 5 36 7 64 9)
Get rid of use with iffi: a two-argument iff with an implicit identity else:

  3> (mapcar [iffi oddp square] 0..10)
  (0 1 2 9 4 25 6 49 8 81)
Now about the point about Lisps and if: the regular if operator with value and expression arguments has a companion if function:

  4> (special-operator-p 'if)
  t
  5> (fboundp 'if)
  t
Unlike in some other dialects like Common Lisp, a symbol can have a binding in the macro or operator space, and in the function space at the same time.

But this if is not useful control. It's useful for things like being able to map over a function-like facsimile of the if operator. E.g. take an element of the (a b c d) or (x y z w) list depending on whether the leftmost list has a nil or t:

  6> [mapcar if '(nil t nil t) '(a b c d) '(x y z w)]
  (x b z d)
In the reverse direction, being able to write a macro for a function function exists, allows for ordinary macros to be "compiler macros" in the Common Lisp sense: provide optimizations for certain invocations of a function.

This dialect is not even "weird"; overall it is Common-Lisp-like. Right down to the multiple namespaces, which is why the [...] syntax exists for referring to functions and variables in a combined virtual namespace.

Re: When if is just a function

#27
post #24
post #9

Earlier quoted context omitted.

Any concrete feedback on looping mechanisms being confusing is appreciated.

Certainly: I can tell the rye devs like the idea of everything being a function. But in their very first "language basics" section, they introduce assignment not as a function call, but as some kind of magic that happens when you have colons in a name. So when we get to the "looping" section, it is the first time we have seen a colon-having-name outside the context of assignment: > loop 3 { ::i , prns i } And it is e…

Rye is foremost a REBOL and REBOL has this notion of many types of words at it's core:

`word` - regular word, can evaluate to value it's bound to or call a funtion if bound to a function

`word: "value"` - set-word, assignment that you noticed

`probe :word` - get-word, always returns bound value, doesn't call a function if it's bound to a function, in Rye this is `?word`, because `:word` is left-set-word.

`'word` - literal word, evaluates to a word itself

etc ...

Rye adds even more word types. Rye also has left to right flow so it adds left-set-word. In Rye all assigned words with set-words are constants and they are used by default. So we also need a "mod-word", that is the double colon that you noticed, and left-mod-word. Because of left-to-right flow Rye also has .op-words and |pipe-words.

The logic around words, op-words and pipe-words ... I tried to explain here:

https://ryelang.org/meet_rye/specifics/opwords/

Another pattern you noticed (good observation btw:) is the idea of injected blocks that isn't used just for loops, but also for conditionals, function bodies, HOF-like functions etc ...

https://ryelang.org/meet_rye/specifics/injected_blocks/

All in all it is supposed to be a compact set of ideas that fit together. Some are somewhat unusual.

Re: When if is just a function

#28
post #24
post #9

Earlier quoted context omitted.

Any concrete feedback on looping mechanisms being confusing is appreciated.

Certainly: I can tell the rye devs like the idea of everything being a function. But in their very first "language basics" section, they introduce assignment not as a function call, but as some kind of magic that happens when you have colons in a name. So when we get to the "looping" section, it is the first time we have seen a colon-having-name outside the context of assignment: > loop 3 { ::i , prns i } And it is e…

If you treat assignment as a function, then you have to reify environments as run-time objects, whereby you basically lose lexical scope.

Lisp originally, as in LISP, had assignment as a function: it was called SET.

To use it, you usually had to quote: (SET 'VAR 42).

It worked without an environment parameter because variables were in a pervasive environment, but the quote was needed to get the variable symbol as a run-time value. (SET VAR 42) would mean evaluate VAR to a symbol, and then pass that symbol to the SET function along with 42, so whatever variable was in VAR would be assigned.

Assignment is inherently non-functional, since it is a side-effect, so it is mostly counterproductive to model it as a function.

A pattern matching or logical language can have implicit bindings as the results of an operation, and so produce variables that way. Then instead of assignment you have shadowing, in that some construct binds a variable again that was already used, so that the most recent value then emerges, shadowing the previous one.

Re: When if is just a function

#29
post #27
post #24

Earlier quoted context omitted.

Certainly: I can tell the rye devs like the idea of everything being a function. But in their very first "language basics" section, they introduce assignment not as a function call, but as some kind of magic that happens when you have colons in a name. So when we get to the "looping" section, it is the first time we have seen a colon-having-name outside the context of assignment: > loop 3 { ::i , prns i } And it is e…

Rye is foremost a REBOL and REBOL has this notion of many types of words at it's core: `word` - regular word, can evaluate to value it's bound to or call a funtion if bound to a function `word: "value"` - set-word, assignment that you noticed `probe :word` - get-word, always returns bound value, doesn't call a function if it's bound to a function, in Rye this is `?word`, because `:word` is left-set-word. `'word` - li…

> Rye also has left to right flow so it adds left-set-word. In Rye all assigned words with set-words are constants and they are used by default. So we also need a "mod-word", that is the double colon that you noticed, and left-mod-word

So I would assume that the :i is actually constant within the loop body scope. That is, the loop function is doing something like this:

; i is not assigned in this scope

evaluate {1 :i, prns i}

evaluate {2 :i, prns i}

evaluate {3 :i, prns i}

; i is still not assigned in this scope

But it sounds like you're telling me that :i would actually escape the scope of the loop body and so it needs to be modifiable or else the loop will break.

Re: When if is just a function

#30
post #15

Seems a bit like Tcl, which lets you create your own control structures like that.

I don't know a lot about Tcl, but one thing I know is said for it "everything is a string". In REBOL's it's somewaht reverse as all this live code are REBOL (Rye) values and REBOL (and Rye) have an unusual number of datatypes, REBOL 30+ (many literal types), which it uses as additional information for functions to work with, and is usefull at creating dialects

For example file-path, url and email address are distinct types in REBOL where in mosta languages are just strings.

Post reply on HN