Why doesn't SML allow if-then without else? - functional-programming

In Standard ML, what was the reasoning behind having if-then-else as a single expression and not allowing only if-then without else clause?
Is it possible to write conditional statements in SML without the else clause?

Standard ML programs are expressions, not statements.
Standard ML is a functional programming language with some impure features. Programs written in Standard ML consist of expressions to be evaluated, as opposed to statements or commands [as found in C-like languages] ..
As such, because if-then-else is an expression, it must evaluate to a value. If the else was not required then the expression would effectively "have no value" if the condition failed - but by definition of an expression, it must have a value. Requiring an explicit else ensures that the expression will evaluate to value in both cases1.
Furthermore, the type from the then and else expressions must be unified - this will be the type of the entire if-then-else construct.
That is, if-then-else in SML is like the ternary (?:) operator in C-like languages, which also shares this "restriction". It is not equivalent if-statements whose branches are evaluated for side effects only.
1 Not all functional-like languages require an explicit then expression and some will default to a particular value. However, this is just how it works in SML which makes sense because there need not be a "default value" for any particular type and the resulting types must be unified.

This isn't specific to Standard ML; many or most languages with if-then-else expressions require an else-expression. For example, in C-like languages (C, C++, C#, Java, D, Perl, JavaScript, PHP, etc.), the expression takes the form cond ? expr_if_true : expr_if_false; in Visual Basic the Iif function requires both an expression-if-true and an expression-if-false; and so on. (There are some languages, such as the Excel formula language, that do not require both values, and substitute a default for the else-expression, but SML is hardly exceptional in not doing so.)
Is it possible to write conditional statements in SML without the else clause?
SML doesn't have any concept of "statements", let alone "conditional statements". It has declarations, but it doesn't make sense to declare something only conditionally (since type information is all determined at compile-time, whereas conditions of course can't be evaluated until run-time).
If you want to take a certain action when a condition is true, and take no action when the condition is false, you just need to use a conditional expression where only the then-expression has a side effect. For example:
val _ = if i > 30 then print "i is too big!" else ()
(where print "Yay!" and () are both expressions of type unit).

I understand what you are saying, but if the "if" statement of your function returns false then the program doesn't know what to do. You probably just want the function to keep going if the expression is false....right?
If you want that to happen then you have make your "else" do something that just passes on to the rest of the function.
I actually don't know much about SML so i couldn't tell you how to do that

Because otherwise, what would be the value of the expression if the if branch does not match? To not need the else branch would require a default value can be inferred. The only thing I see which could make sense, is to raise an exception. Could have been an option for the design of SML, but this was not and would not have been a lot relevant any way.
Whenever you feel there is no valid expression value on else, then just say something like this:
val x =
if condition then expression
else raise Domain;

Related

What's the theoretical loophole that allows F# (or any functional language) to apply a function mulitple times on the same input

In F# if I write
let p = printfn "something"
it will evaluate the expression once. Any subsequent references to p will evaluate to unit.
From a theoretical perspective, the definition of a function, this makes sense. A function should only return the same result for the same input.
However if I want the side-effect to occur (i.e. the output to the screen), then I need the pass an argument to p. Typically this argument is the unit value.
let p () = printfn "something"
But why will F# evaluate the function each time, when the argument is the same each time the function is applied? Surely the same reasoning should apply as in the first case? The input to the function p doesn't change therefore there is no need to evaluate it more than once.
The action printfn is, strictly speaking, not a function. It is, particularly, not a pure function, because it's not referentially transparent. This is possible because F# isn't a strictly functional language (it's a 'functional first' language). It makes no explicit distinction between pure functions and impure actions.
The return value of printfn "something" is () (unit), which means that p is bound to the unit value (). The fact that something is printed on the screen is a side effect of evaluating the expression.
F# is an eagerly evaluated language. That's why you see something printed on the screen as a side effect of binding printfn "something" to p. Once the expression is evaluated, p is only bound to () - the value.
F# doesn't memoize function calls, so when you change p to a function, it'll evaluate the function every time you call it with (). Since all functions can be impure, the compiler can't tell whether or not memoization would be appropriate, so it doesn't do that.
Other languages do this in different ways. Haskell, for example, is lazily evaluated, and also explicitly distinguishes between pure functions and impure actions, so it can apply different optimization in cases like these.
To expand on the answer given in the comments, the first p is an immutable value, while the second p is a function. If you refer to an immutable value multiple times, then (obviously) its value doesn't change over time. But if you invoke a function multiple times, it executes each time, even if the arguments are the same each time.
Note that this is true even for pure functional languages, such as Haskell. If you want to avoid this execution cost, there's a specific technique called memoization that can be used to return cached results when the same inputs occur again. However, memoization has its own costs, and I'm not aware of any mainstream functional language that automatically memoizes all function calls.

R's switch statement is not a special form, is it therefore slow?

In most languages with switch statements, switch is a special form designed such that the possibilities are evaluated lazily and the compiler knows how to optimise the selection of statements based on the given input. R, mostly already being lazy, does not need some of this. However, R's switch statement is still a function call, rather than any sort of special form. Does this mean that R's switch statement is slower than it would be if it were a special form? Or does R's interpreter know to optimise it as if it were a special form?
If you look at internal code of switch in file src/main/builtin.c, you can read in lines 1009-1025 :
This is a SPECIALSXP, so arguments need to be evaluated as needed.
SPECIALSXP means :
no SEXPTYPE Description
7 SPECIALSXP special functions
So switch is actually a special function which passes unevaluated arguments to the internal function.
Further reading the source code from line 1030 to line 1104 shows that as explained in ?switch, the function either handles character or number in a simple and not fully optimized way.
This probably explains why switch isn't particularly fast in situations which would for example require a binary search.

Connection between functional programming and term rewriting

I am interested in the use of term rewriting systems and I found that term rewriting "helps for basic reasoning about functional programs", but I can't understand what it means. I haven't worked with functional programming, but I know the main principles, like pure functions and immutability. Still, I can't get what basic reasoning refers to. Also, is it somehow connected to the inversion of term rewriting?
They are "connected" because they rely on the same concept: everything is an expression:
In term rewriting, computation is performed by the searching of patterns in expressions, and then the changing of the matched expressions (or subexpressions) to other expressions (rewriting). As a very simple example, the expression 2 + 3 can be transformed into the expression 5 because there is a rewriting rule (that we know as "numerical addition") that knows how to perform such that transformation.
In functional programming languages, a function is a "first class citizen" of the language, it can be said as "everything is an expression, including a function". So a function can be specified as an argument for function (or procedure) calls, or a function (or a procedure) can return a function (higher-order functions) just like it is done with primitive types.
Additionally, because in in term rewriting "everything is an expression", every one of them must yield a value, just like a function, so a computation by term rewriting can be seen as a successive application of functions.

What does the jq notation <function>/<number> mean?

In various web pages, I see references to jq functions with a slash and a number following them. For example:
walk/1
I found the above notation used on a stackoverflow page.
I could not find in the jq Manual page a definition as to what this notation means. I'm guessing it might indicate that the walk function that takes 1 argument. If so, I wonder why a more meaningful notation isn't used such as is used with signatures in C++, Java, and other languages:
<function>(type1, type2, ..., typeN)
Can anyone confirm what the notation <function>/<number> means? Are other variants used?
The notation name/arity gives the name and arity of the function. "arity" is the number of arguments (i.e., parameters), so for example explode/0 means you'd just write explode without any arguments, and map/1 means you'd write something like map(f).
The fact that 0-arity functions are invoked by name, without any parentheses, makes the notation especially handy. The fact that a function name can have multiple definitions at any one time (each definition having a distinct arity) makes it easy to distinguish between them.
This notation is not used in jq programs, but it is used in the output of the (new) built-in filter, builtins/0.
By contrast, in some other programming languages, it (or some close variant, e.g. module:name/arity in Erlang) is also part of the language.
Why?
There are various difficulties which typically arise when attempting to graft a notation that's suitable for languages in which method-dispatch is based on types onto ones in which dispatch is based solely on arity.
The first, as already noted, has to do with 0-arity functions. This is especially problematic for jq as 0-arity functions are invoked in jq without parentheses.
The second is that, in general, jq functions do not require their arguments to be any one jq type. Having to write something like nth(string+number) rather than just nth/1 would be tedious at best.
This is why the manual strenuously avoids using "name(type)"-style notation. Thus we see, for example, startswith(str), rather than startswith(string). That is, the parameter names in the documentation are clearly just names, though of course they often give strong type hints.
If you're wondering why the 'name/arity' convention isn't documented in the manual, it's probably largely because the documentation was mostly written before jq supported multi-arity functions.
In summary -- any notational scheme can be made to work, but name/arity is (1) concise; (2) precise in the jq context; (3) easy-to-learn; and (4) widely in use for arity-oriented languages, at least on this planet.

Other ternary operations than conditional expression

I read on Wikipedia that there are often only one ternary operation type possible in C-like languages, which is the conditional expression.
I am trying to find out what other ternary operation exists and what language would make use of them.
Some languages have ternary or even variadic comparison operators, so you can write things like “0 <= x < 15”.
I wonder whether things like “<expression> for <variable> in <list>” from python could be considered a ternary operator as well. If you argue that the variable name in there is not an expression, then you could use the “<expresstion> for <variable> in <list> if <condition>” where expression, list and condition are arbitrary expressions. The specification lists generator expressions in the same section as most operators, but doesn't call it an operator and doesn't list it in the table for operator precedence.
Many RISC architectures use three operands for common arithmetic operations: two to indicate input values and one to denote the result. Whether you'd call that an operator, and the result register an argument to that operator, is of course again a matter of perspective.
In general, many languages have a far less clear line distinguishing operators from functions on the one side or control constructs on the other side. In those cases it is often hard to decide whether some ternary construct is indeed an operator or not.

Resources