Haskell also has definitions, which can't be used as expressions directly, e.g. we can write:
foo = bar
But we can't write:
baz = 2 + (foo = bar)
I this case we can get the expected return value by using 'let... in...' syntax, but we wouldn't get the top-level definition, e.g.
baz = 2 + (let foo = bar in foo)
Likewise for type definitions, class definitions, etc.
One language which handles definitions nicely as expressions is Nix. Nix has 'let' but I never use it. Instead we can use 'with':
with {
foo = bar;
};
"hello " + foo
The thing in braces isn't a block of statements; it's a key/value dictionary (Nix calls them 'attribute sets' or 'attrsets'). The 'with...; ...' syntax acts like 'let... in...' but both pieces are expressions.
with {
myAttrs = {
foo = bar;
};
};
with myAttrs;
"hello " + foo
Interestingly, whilst Lisp distinguishes between 'letrec' and 'let' (bindings with and without mutual/self-reference, respectively), Nix distinguishes between 'rec {...}' and '{...}' (attrsets with and without mutual/self-reference). In other words, when we write 'with rec {...}' the 'rec' modifier affects the definition of the attrset (the '{...}'), it doesn't affect the binding of that attrset into the environment (the 'with'). For example:
with {
bar = 42; // To prevent nonRecursive complaining about a missing variable
recursive = rec {
foo = bar + 1; // The number 6, since 'bar' is taken from this
bar = 5; // The order of definitions doesn't matter
}; // The attrset { foo = 6; bar = 5; }
nonRecursive = {
foo = bar + 1; // The number 43
bar = 5;
}; // The attrset { foo = 43; bar = 5; }
};
// [] is syntax for a list
[
(with recursive; foo) // The number 6
(with nonRecursive; foo) // The number 43
] // The list [6 43]
Of course, attrsets (recursive or not) can be used as expressions:
(rec { foo = bar + 1; bar = 5; }).foo // The number 6
One language which handles definitions nicely as expressions is Nix. Nix has 'let' but I never use it. Instead we can use 'with':
The thing in braces isn't a block of statements; it's a key/value dictionary (Nix calls them 'attribute sets' or 'attrsets'). The 'with...; ...' syntax acts like 'let... in...' but both pieces are expressions. Interestingly, whilst Lisp distinguishes between 'letrec' and 'let' (bindings with and without mutual/self-reference, respectively), Nix distinguishes between 'rec {...}' and '{...}' (attrsets with and without mutual/self-reference). In other words, when we write 'with rec {...}' the 'rec' modifier affects the definition of the attrset (the '{...}'), it doesn't affect the binding of that attrset into the environment (the 'with'). For example: Of course, attrsets (recursive or not) can be used as expressions: