When if is just a function
49 comments
·October 14, 2025veqq
roxolotl
Do you have any recommendations for a language where you _have to_ use these concepts. I love playing with them but I find that unless i’m paying a lot of attention in most cases I fall back to a less functional style even in a language like Janet. I’d love to find a language where you largely have to use these combinatorial logic style functions so I can’t just default back to other styles.
veqq
J and BQN (APL has off-ramps...)
https://code.jsoftware.com/wiki/Essays/Tacit_Expressions
https://mlochbaum.github.io/BQN/doc/tacit.html and https://mlochbaum.github.io/BQN/doc/control.html
Forth, Factor and Uiua (which combines the above approach) don't use these concepts yet are also inherently point-free, and without lambdas so you definitely wouldn't be able to rely on functional techniques!
huflungdung
[dead]
ivanjermakov
The drawback is that this approach elevates code blocks to first class. It means that there is a semantical difference between a value that is a block and a value that is a result of a block. This reduces code clarity, because now block def/result is discriminated by context instead of syntax.
- closures get tricky, i.e. having outer scoped variables within a block
- inter-block operators still need special care, e.g. return should return from a function or a nearest block, same for break/continue/etc.
hatthew
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 there is a broad consensus that reflection is a Bad Idea.
Open to being convinced otherwise
(tangent but related, aren't the "Loops" and "Iteration" examples given for python literally the exact same syntax, with the exception of changing how the iterable is generated?)
Nevermark
> 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.
hatthew
That makes sense, thanks!
hshdhdhehd
I agree. In any somewhat functional language (I.e. all the mainstream ones) you can wrap "if" in a function if you please.
E.g.
function funif (b, f) {
return (b && f())
}
If you want to do clever stuff. I never feel the need as I would rather abstract over bigger things.solomonb
Given an algebraic data type such as:
data List a = Nil | Cons a (List a)
You can define its recursion principle by building a higher-order function that receives an element of your type and, for each constructor, receives a function that takes all the parameters of that constructor (with any recursive parameters replaced by `r`) and returns `r`.For `List` this becomes:
foldr :: (() -> r) -> (a -> r -> r) -> List a -> r
The eliminator for `Nil` can be simplified to `r` as `() -> r` is isomorphic to `r`: foldr :: r -> (a -> r -> r) -> List a -> r
foldr z f Nil = z
foldr z f (List a xs) = f a (foldr f z xs)
For `Bool`: data Bool = True | False
We get: bool :: a -> a -> Bool -> a
bool p q True = q
bool p q False = p
Which is precisely an If statement as a function!:D
ozy
Useless unless the logical operators receive their rhs unevaluated. And that is generalized as a language feature.
sparkie
A general language feature would be fexprs, or call-by-name (which can be combined with call-by-value using call-by-push-value).
In Kernel[1] for example, where operatives are an improved fexpr.
($define! $if
($vau (condition if-true if-false) env
($cond
((eval condition env) (eval if-true env))
(#t (eval if-false env)))))
$vau is similar to $lambda, except it doesn't implicitly evaluate its operands, and it implicitly receives it's caller's dynamic environment as a first class value which gets bound to env.$lambda is not actually a builtin in Kernel, but wrap is, which constructs a function by wrapping an operative.
($define! $lambda
($vau (args . body) env
(wrap (eval (list* $vau args #ignore body) env))))
[1]:https://ftp.cs.wpi.edu/pub/techreports/pdf/05-07.pdfanalog31
Interestingly, Excel provides "if" as a function:
=if(condition, value-if-true, value-if-false)
jrochkind1
Smalltalk, anyone? I guess the OO version.
sebastianconcpt
Yeah, here. They should know the feeling of booleans as instances and ifTrue: ifFalse: as methods. But for us is such an obvious thing that isn't really something too remarkable. It normalized language awesomeness.
middayc
There is a language https://sprylang.se/index.html which started more as Rebol and moved towards Smalltalk.
spankalee
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.
iamevn
See the `either` function further down
either some-condition { print "was true" } { print "was false" }
middayc
there is no if { } else { } in REBOL or Rye and it wouldn't really fit. There is either function that accepts two code blocks. It can act as a typical if / else or as a ternary expression as it also returns the result of a block:
print either pwd = "correct" { "Hello" } { "Locked" }
This is Rebol's doc on either, Rye's works exactly the same:
https://www.rebol.com/docs/words/weither.htmlnull
icepat
Is this just a quirk in my display, or are all the code blocks in this formatted like a CIA black highlighter
singlow
It's only a problem if I have my browser set to use dark theme or system theme and my system theme is dark if I switch it to light theme. Everything looks good. So most likely he's using some kind of CSS framework that's automatically responding to the dark theme, but other styles that he's hand coded are not compatible with it
middayc
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.
blauditore
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.
middayc
I fixed it thanks! I was able to activate dark more in Firefox on desktop and find problems with CSS.
middayc
Thank you all for heads up! I was playing with CSS and didn't test the dark mode. I think it's fixed now.
null
null
davidw
Seems a bit like Tcl, which lets you create your own control structures like that.
middayc
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.
Combinatory programing offers functional control flow. (Here is a straight forward explanation: https://blog.zdsmith.com/series/combinatory-programming.html ) I was inspired to write `better-cond` in Janet: