Comments (14)
@OvermindDL1 @saem I missed the distinction between open
and include
where it sounds like the former serves almost as a sort of "default implementation" or simple inheritance mechanism. The function import stuff in PR #84 and the semantics/overriding I described are applicable only to the include
side of OCaml of course. The open
examples are really interesting but I think that if we chase something similar it has significantly broad enough implications that it warrants some care with a much longer view and as such I think we should probably have a separate discussion (or many perhaps) about it and how it might interact with something like signatures and modules vs traits and implementations vs type classes, etc.
My basic opinion right now: I see value in default implementations of signatures/interfaces but would like to consider more specificity than open
appears to provide. Thoughts? Links to papers most definitely appreciated :D I have opened issue #90 for this purpose.
@yurrriq with respect to sequential let I'm firmly in the same camp as you. I'm honestly not sure what the utility of (let ...)
is :) Top-level bindings are let rec
mostly because they are in Erlang as well and I didn't see a particularly good reason for them not to be but I'm more than happy to hear reasons counter!
As for separators I don't have any really strong feelings aside from not using significant whitespace. @ypaq I think was right to push for its removal in IRC and @lepoetemaudit just went through a fair bit of work removing the need for it (part of the reason we now have leading let
s and a h/t to @ypaq again for all the property based tests to help shake out more bugs). I suggested ;
for the separator only because it currently has no use/meaning in Alpaca.
from alpaca.
I'd say no on that personally. That is a Haskell'y format that implies that they can be recursively defined, which I highly doubt is the case here?
from alpaca.
In regards to the question about where
raised by @yurrriq's, a long debate has been going on in Elm, and there is a particularly good summary of it by Colin Woodbury.
It's interesting covering a number of issues around git diffs, action to intent/return distance, etc...
I do think that it's a nice to have, and people can make do in the mean time, so it wouldn't be unreasonable to sideline it for now.
from alpaca.
👎 from me. I would prefer there to be only one way to create variables and this new syntax does not add anything not already possible with the existing syntax.
from alpaca.
To clarify, do you mean that it would imply we can define recursive functions in the let binding or that functions in the sequence can refer to ones previously defined in the same sequence?
from alpaca.
To clarify, do you mean that it would imply we can define recursive functions in the let binding or that functions in the sequence can refer to ones previously defined in the same sequence?
As in the syntax given reminds of the Haskell syntax where you can define recursive functions, a trivial example:
let
blee x =
| x <= 0 = 0
| otherwise = blah x
blah x = bleh (x - 1)
in blah 42
In Haskell such a form is naturally recursive, the equivalent form in OCaml, as an example, could be:
let rec blee = function
| x when x<0 -> 0
| x = blah x in
and blah x = bleh (x - 1) in
blah 42
Also, if your function returns unit in OCaml, you can elide the let .. in
construct to just a trailing ;
, thus these are equivilent (and the returning unit part is likely to be enforced in future versions):
let () = someFuncThatReturnsUnit 42 in
someFuncThatReturnsUnit 42;
TL;DR: It would imply to me that the functions within would be mutually recursive, also the ;
is heavily overloaded for my mental state as it is, so using it as a separator within a let binding feels very odd. ^.^
from alpaca.
Ah, I think I see. So in Alpaca atm all function bindings are actually let rec
(in the Core Erlang AST) and there's no special syntax for mutually recursive functions, e.g.
let a () = b ()
let b () = a ()
is perfectly fine (assuming top-level bindings for both here). Both have the return type "infinitely recursive" (t_rec
in the typer's paralance). Having said all that I can definitely see how the way I framed this could be confusing :)
I should have been a bit more specific, I was referring to bindings within top-level functions/bindings, e.g.
let foo () =
let add x y = x + y in
let square x = x * x in
add 2 (square 3)
vs
let foo () =
let
add x y = x + y;
square x = x * x
in add 2 (square 3)
Better/worse? Totally open to different separators.
from alpaca.
I should have been a bit more specific, I was referring to bindings within top-level functions/bindings, e.g.
I meant the same. ^.^
I definitely prefer the let .. in
syntax personally, but then again I prefer OCaml syntax over Haskell, so I am biased. ^.^
(In OCaml, the 'rec' is not default not because it would slow down compilation or anything, but because OCaml lets you 'name' a function then overwrite it later to be exposed, and this is entirely doable in the Erlang AST as well by just having the non-exposed variants have private unique names. OCaml uses this so that you can do things like open Some.Module
, which imports all of the functions in that module into the scope here (exposing them publicly as well, if you do not want that then use include Some.Module
instead), thus you can expose an identical interface from another module but with some custom overridden functions or added functions, so you could do something like open Map
into your own MyMap
module, then overwrite the get
function so that instead of throwing an exception on failure it would return an 'key option
instead for example. It has other great uses that Haskell just cannot emulate well as well. :-) )
from alpaca.
Interesting...bindings within top-level bindings in Alpaca are rewritten/renamed with synthetic/unique names but then checked for collision with bindings created later, e.g.
let f () =
let x = 2 in
let y = x +2 in
let x = 3 in
x +y
will generate a duplicate definition error. The motivation behind the check is to explicitly remove the ability to shadow things, especially with respect to changing types and renaming is to avoid a few issues with names escaping receive
s.
With respect to the open
syntax you mentioned, function imports (see PR #84) I think will do what you're describing. An explicit module.function
reference will win over a local definition but a local definition will always win over an imported one. Having said that, things like OCaml's signature and module system haven't really been discussed yet and should be soon! I'm not entirely sure which way I want to jump but I do like things like:
- programming to an interface (signatures)
- dependency injection (can kind of do this with functors? @saem and I have talked a little about this, it's one of the few things about OOP we both like)
I think this sort of thing does help address Erlang behaviours or something like them as well. @Tuncer and I talked a little bit about things like 1ML and a few other things a while back but to be perfectly honest I've got a lot more reading and understanding to do :) I may be getting into the weeds a bit here, probably a better discussion for a new issue or on irc.
from alpaca.
In regards to the points raised in this thread:
- Repeated
let ... in
vslet ... $SEPARATOR ... in
The latter reads more nicely than the former (pure opinion), from the perspective that I like code to come off as a narrative. Repeated let ... in
s are clunky. But I'm trying to think about it from @OvermindDL1's perspective, in terms of what other subtleties does this imply.
let
vslet rec
might be a worth while distinction
Borrowing from OCaml (which I know little about), and this explanation about let
vs let rec
, and why one might care, it seems the distinction is worthwhile. Given let rec
, and let nonrec
behaviour, I'm not sure what you'd want a let
to default to.
from alpaca.
In LFE, people seem to strongly dislike like the distinction between (let ...)
, as in:
let x = 42
y = x + 1 (* Error: x is undefined) *)
in ...
... and (let* ...)
let x = 42
y = x + 1
in ... (* y = 43 *)
In those terms, Clojure defaults to the let*
(henceforth sequential let) behaviour.
As far as that concern, I'd prefer sequential let. As far as the let
vs let rec
discussion, I'd prefer an explicit rec
, as in local functions defined with just let
are not recursive (but can refer to local definitions that precede them).
For the separator, I like "new line and leading indentation match" and maybe ;
, as in:
let x = 42
y = x + 1
in ...
or
let x = 42
y = x + 1 in
...
and maybe
let x = 42; y = x + 1 in ...
Does Alpaca have a where
keyword?
from alpaca.
Top-level bindings are let rec mostly because they are in Erlang as well and I didn't see a particularly good reason for them not to be but I'm more than happy to hear reasons counter!
They do not need to be though. The external interface for a module is defined explicitly in the EVM so you could easily build up a list of internal functions with the final defined set being the ones that are actually exposed (rename prior). :-)
from alpaca.
Oh definitely possible yes :)
My reluctance to go this direction is an assumption that most people coming from languages other than OCaml might naturally expect functions to be essentially let rec
by default, e.g. from Erlang, Haskell, Scala, etc. In terms of the discussion in #90 about open
and default implementations I'd almost prefer an explicit override rather than (what feels to me like) implicit behaviour.
open
, etc aside, are there things I'm missing/unaware of that aren't possible or rendered more difficult given the import semantics in PR #84 ?
PS I really appreciate the input/feedback/ideas.
from alpaca.
@saem that's a really great post, thanks for linking it! "Intent first" is an interesting way to put it and I think a good argument in favour of us adding where
at some point. I don't think it would be particularly difficult to do entirely on the parser side of things either, no AST nor typer changes would be necessary.
from alpaca.
Related Issues (20)
- Function parsing as incorrect arity with ADT as first arg HOT 2
- Auto-imported pipe operator HOT 2
- Treat types with a single unqualified member as aliases HOT 1
- Overlap between function heads and match expression HOT 1
- How to type Erlang terms without built-in types. HOT 7
- alias module name HOT 1
- Zero arity functions HOT 5
- Inconsistent function case HOT 2
- Compile error with type signature annotation
- Defining the function (>>) does not yield a helpful error
- Use values to signify test pass/fail rather than exceptions
- Can't find a way to contact the creator/mantainers of alpaca :) HOT 2
- ReasonML HOT 4
- provide prebuilt "binaries" for OTP 21
- Status? HOT 4
- "Overloaded" records with constructors in patterns fail instead of getting a proper warning.
- Incorrect line numbers for missing record field errors
- clarify - nominal or structural type system HOT 3
- ADT argument in function header crashes compiler
- Non-exhaustive patterns in "match" expressions HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from alpaca.