4 ms·
> Rye is homoiconic, it has no keywords or special forms (everything is a function call, everything is a value) How does it implement and, or, or if?
by gumby 3y ago
> Rye is homoiconic, it has no keywords or special forms (everything is a function call, everything is a value)
How does it implement and, or, or if?
- chabons 3y agoPresumably as functions, the same way as excel? and(x, y) -> bool or(x, y) -> bool if(cond, funcTrue, funcFalse) -> void
- adrianmsmith 3y agoYeah I did notice in the examples fac: fn { x } { either x = 1 { 1 } { x * fac x - 1 } } ; function that calculates factorial So presumably "either" is the "if" expression.
- anamexis 3y ago"if" is the "if" expression - https://ryelang.org/meet_rye/basics/if_either/ https://ryelang.org/meet_rye/basics/if_either/
- acjohnson55 3y agoYeah, but "either" is the if-else construct, so the person you replied to isn't really wrong.
- deleted 3y ago[deleted]
- sparkie 3y agoif(and(or(cond1, cond2), cond3), effect1(), effect2()) In most languages, if `cond1` evaluates to true, you would not evaluate `cond2`. If `cond1` and `cond2` evaluate to false, you would not evaluate `cond3`. If all conds evaluate to false, you would not evaluate `effect1()`, and if `cond3` and either `cond1` or `cond2` are true, you would not evaluate `effect2()` They're not functions because they don't evaluate their arguments before evaluating their body. Their operands are passed verbatim and evaluated explicitly by the body on demand. In Kernel, for example, we can define these as operatives, which don't evaluate their operands. Assuming we have some primitive operatives `$cond`, `$define!` and `$vau` (the constructor of operatives), and an applicative `eval`: ($define! and ($vau (lhs rhs) env ($cond ((eval lhs env) (eval rhs env) (#t #f))))) ($define! or ($vau (lhs rhs) env ($cond ((eval lhs env) #t) (#t (eval rhs env))))) ($define! if ($vau (condition consequent antecedent) env ($cond ((eval condition env) (eval consequent env)) (#t (eval antecedent env))))) These aren't the definitions Kernel uses in its standard environment. It uses recursive definitions of `$and?` and `$or?` which take arbitrary number of operands, and `$cond` is defined in terms of `$if`, which is primitive: ($define! $cond ($vau clauses env ($if (null? clauses) #inert ($let ((((test . body) . rest) clauses)) ($if (eval test env) (apply (wrap $sequence) body env) (apply (wrap $cond) rest env)))))) ($define! $and? ($vau x env ($cond ((null? x) #t) ((null? (cdr x)) (eval (car x) env)) ((eval (car x) env) (apply (wrap $and?) (cdr x) env)) (#t #f)))) ($define! $or? ($vau x env ($cond ((null? x) #f) ((null? (cdr x)) (eval (car x) env)) ((eval (car x) env) #t) (#t (apply (wrap $or?) (cdr x) env)))))
- anamexis 3y agoI don't think that's what Rye is doing. It's doing if(cond, effect1, effect2) where effect1 and effect2 are functions, and only evaluating the matching effect function. But everything is functions.
- middayc 3y agotechnically effect1 and effect2 are so called "blocks of code" in rebol/rye/red/... Everything being a function is trying to say that every "active word" (a word that does something ... print, first, if, fn, context, extends, ...) is just a function.
- samatman 3y agoThis is possible with fexprs or equivalent constructs https://en.wikipedia.org/wiki/Fexpr https://en.wikipedia.org/wiki/Fexpr It looks like that's how Rye does it as well, blocks can be conditionally evaluated: https://ryelang.org/meet_rye/basics/if_either/ https://ryelang.org/meet_rye/basics/if_either/ "In REBOL, contrary to Lisps, blocks or lists don’t evaluate by default. For better or for worse, this little difference is what makes REBOL - REBOL." https://ryelang.org/meet_rye/basics/doing_blocks/ https://ryelang.org/meet_rye/basics/doing_blocks/ It's difficult for a language with this semantics to be made efficient, but efficiency isn't everything.
- fuzztester 3y ago>programming language based on ideas from Rebol, flavored by Factor, Linux shell and Go That makes it potential interesting to me.
- fuzztester 3y agopotentially, autocorrect incorrect :)
- _nalply 3y agoWhy is it difficult?
- samatman 3y agoSince code-is-data, you can put that exact if statement into several functions. Since code-is-data, you can swap the if and else clauses around. This applies to all the functions where you've inserted the if statement. This kind of thing makes it difficult to compile a function to a fast set of machine instructions with the same effect. Not impossible, but difficult.
- sparkie 3y agoIt's difficult to optimize because evaluation of expressions depends on the dynamic environment, which you don't have ahead-of-time. You can't even assume `+` means "add the arguments", because `+` may have been bound to something completely different prior to evaluating the expression containing `+`.
- justinpombrio 3y agoThis took me a minute to get, even after looking at the page about if: https://ryelang.org/meet_rye/basics/if_either/ https://ryelang.org/meet_rye/basics/if_either/ The tricky thing about if, and, and or --- the reason you can't implement them as functions in most languages --- is that they need to not evaluate all their arguments immediately. Otherwise: // Would print! if(false, print("oops!")) // Would throw an error if the key is not present and(my_hashmap.has_key("key"), my_hashmap["key"]) The way that ryelang gets around this is that you pass the arguments in a "code block" surrounded by "{}", which delays its evaluation. So you write: // Does not print, because *if* never runs its code block arg if 0 { print("oops!") } // There's no example of *and* anywhere but my guess is you'd write this: and { my_hashmap.has_key("key") } { my_hashmap["key"] }
- nerdponx 3y agoThe R language has this feature as well. It's a whole lot of fun to work with.
- dmux 3y agoLikewise in Tcl where blocks can either be sent quoted (using {}) or unquoted (using “”). In the latter, variables and procs will have a round of substitution performed before being passed to the proc.
- middayc 3y agoRebol (where Rye took this from) is many times associated with Tcl. I've heard good things about it, but haven't really tried it yet.
- spindle 3y agoTCL is kinda similar to Rebol in some ways but in other ways it's the opposite of Rebol, because in TCL everything is a string (although it can ALSO have another type, thanks to clever shenanigans). (You probably knew this!)
- middayc 3y agoYes, as samatman said, main reason is that blocks of (code or data there is no difference) don't evaluate so they are passed as function arguments and the function can potentially evaluate them. So if is a function that accepts two arguments, a boolean and a block of code. loop is a function that also accepts two, integer for number of loops and again a block of code. Even fn that creates functions is a function that accepts two blocks, first is a list of arguments and second is a block of code. There is no big difference between function fn and function print, they are both builtin functions defined in same manner and there are multiple fns for special cases and you can create your own on "library" level.
- choeger 3y agoIn a eagerly evaluating functional language you could always wrap the arguments in a thunk: So if your built-in functions were implemented in Python, you'd use: def if_(cond, t, e): if cond: return t() else: return e()
- deleted 3y ago[deleted]