4 ms·
fn/n where n is parity of fn was confusing for me at first, but then I started to like the idea, esp. in dynamic languages it's helpful to have at least some se
by behnamoh 2y ago
fn/n where n is parity of fn was confusing for me at first, but then I started to like the idea, esp. in dynamic languages it's helpful to have at least some sense of how things work by just looking at them.
this made me think about a universal function definition syntax that captures everything except implementation details of the function. something like:
fn (a: int, b: float, c: T) {foo: callable, bar: callable, d: int} -> maybe(bool | [str] | [T])
which shows that the function fn receives a (integer), b (float), c (generic type T) and maybe returns something that's either a boolean or a list of strings or a list of T, or it throws and doesn't return anything. the function fn also makes use of foo and bar (other functions) and variable d which are not given to it as arguments but they exist in the "context" of fn.
- jlarocco 2y agoMeh, if I need that much detail I'll just read the function. And a function returning one of three types sounds like a TERRIBLE idea.
- c0balt 2y ago> And a function returning one of three types sounds like a TERRIBLE idea. Should have been an enum :)
- arlort 2y agominor nitpick, I think you meant arity. If it's a typo sorry for the nitpick if you had only ever heard it spoken out loud before: arity is the number of parameters (in the context of functions), parity is whether a number is even or odd
- johnisgood 2y agoThe distinctions are important, would not consider it a minor nitpick. :P
- elcritch 2y agoWell Erlang and Elixir both have a type checker, dialyzer, which has a type specification not to far from what you proposed. Well excluding the variable or function captures. Elixir’s syntax for declaring type-specs can be found at https://hexdocs.pm/elixir/1.12/typespecs.html https://hexdocs.pm/elixir/1.12/typespecs.html
- the_duke 2y agoElixir is also working on a proper type system with compile time + runtime type checks.
- itishappy 2y agoLooks similar to how languages with effect systems work. (Or appear to work, I haven't actually sat down with one yet.) They don't capture the exact functions, rather captuing the capabilities of said functions, which are the important bit anyway. The distinction between `print` vs `printline` doesn't matter too much, the fact you're doing `IO` does. It seems to be largely new languages trying this, but I believe there's a few addons for languages such as Haskell as well. https://koka-lang.github.io/koka/doc/index.html https://koka-lang.github.io/koka/doc/index.html https://www.unison-lang.org/docs/fundamentals/abilities/ https://www.unison-lang.org/docs/fundamentals/abilities/ https://dev.epicgames.com/documentation/en-us/uefn/verse-language-reference https://dev.epicgames.com/documentation/en-us/uefn/verse-lan...
- wbadart 2y agoAs I understand it, Erlang inherited its arity notation from Prolog (which early versions of Erlang were implemented in). https://en.m.wikipedia.org/wiki/Erlang_(programming_language)#History https://en.m.wikipedia.org/wiki/Erlang_(programming_language...
- derefr 2y ago> fn/n where n is parity of fn was confusing for me at first, but then I started to like the idea, esp. in dynamic languages it's helpful to have at least some sense of how things work by just looking at them. To be clear, this syntax is not just "helpful", it's semantically necessary given Erlang's compilation model. In Erlang, foo/1 and foo/2 are separate functions; foo/2 could be just as well named bar/1 and it wouldn't make a difference to the compiler. But on the other hand, `foo(X) when is_integer(X)` and `foo(X) when is_binary(X)` aren't separate functions — they're two clause-heads of the same function foo/1, and they get unified into a single function body during compilation. So there's no way in Erlang for a (runtime) variable [i.e. a BEAM VM register] to hold a handle/reference to "the `foo(X) when is_integer(X)` part of foo/1" — as that isn't a thing that exists any more at runtime. When you interrogate an Erlang module at runtime in the erl REPL for the functions it exports (`Module:module_info(exports)`), it gives you a list of {FunctionName, Arity} tuples — because those are the real "names" of the functions in the module; you need both the FunctionName and the Arity to uniquely reference/call the function. But you don't need any kind of type information; all the type information is lost from the "structure" of the function, becoming just validation logic inside the function body. --- In theory, you could have compile-time type safety for function handles, with type erasure at runtime ala Java's runtime erasure of compile-time type parameters. I feel like Erlang is not the type of language to ever bother to add support for this — as it doesn't even accept or return function handles from most system functions, instead accepting or returning {FunctionName, Arity} tuples — but in theory it could.
- toast0 2y ago> But Erlang itself, as a language, doesn't even have function-reference literals; you usually just pass {FunctionName, Arity} tuples around. I don't really understand what a literal is, but isn't fun erlang:node/0 a literal? It operates the same way as 1, which I'm quite sure is a numeric literal: Eshell V12.3.2.17 (abort with ^G) 1> F = fun erlang:node/0. fun erlang:node/0 2> X = 1. 1 3> F. fun erlang:node/0 4> X. 1 I set the variable to the thing, and then when I output the variable, I see the same value I set. AFAIK, both 1 and fun erlang:node/0 must both be literals, as they behave the same; but I'm happy to learn otherwise.