Open paulbutcher opened 2 years ago
Looks good! I have often seen repl in situations where people showcase what types things are so I was wondering what your opinion is about displaying types. In the above its only shown here
User> let x = ref 1
<ref: Int32>
User> x := deref x + 1
<ref: Int32> (note: this should be unit I presume)
User> deref x
2
User>
Should the type display be related to let-bindings, displayed with all values, or shown based on a special repl method?
(note: this should be unit I presume)
Oops, yes, definitely.
Should the type display be related to let-bindings, displayed with all values, or shown based on a special repl method?
That, I'm not sure about. It should be "whatever is most helpful", but I'm not sure what that means, exactly.
How's this as a starting point for when types should be displayed?
ToString
is displayed as-is.So:
User> 1 + 2
3
User> def myFunc(x: Int32, y: String): String = ???
$ Int32 -> (String -> String)
User> enum Piece {case King, Queen, Rook, Bishop, Knight}
$ Piece
User> King
$ Piece
(the intention of the $
(not sure whether this is the best choice, but) being to indicate that what you're seeing isn't the value itself).
Note: the REPL will need to be able to parse “enough” of the input to know whether or not it should display the ...> continuation prompt.
GHCi uses explicit brackets for multiline input. Following this would be simpler for the parser.
GHCi uses explicit brackets for multiline input. Following this would be simpler for the parser.
I guess another option would be some kind of explicit "line continuation" character (e.g. a \
at the end of the line)? Not ideal, but not a disaster either.
You could also, before giving the text to the actual parser, let the user input lines until parentheses match using a simpler parser. This would let you input tuples/records/def using multiple lines (def f(x): Int32 = {
)
GHCi uses explicit brackets for multiline input. Following this would be simpler for the parser.
I guess another option would be some kind of explicit "line continuation" character (e.g. a
\
at the end of the line)? Not ideal, but not a disaster either.
I like this as the starting point. Its simple and easy to explain. Later we can go for something more fancy.
@stephentetley What's the bracket thing? Is it like if you write {
then GHCI knows to look for the closing bracket?
(I guess we can not use brackets because we have them in the language, so we would need something else).
GHCi uses :{
and :}
or it has a multiline mode which looks like it uses a parsing strategy so see if input is finished:
https://downloads.haskell.org/~ghc/8.8.3/docs/html/users_guide/ghci.html#multiline-input
I would propose the following:
If a line ends with \
then we ask for more input until the line does not.
If you enter \\
on a line by itself then the parser keeps asking for input until you enter \\
on a line by itself.
Thus:
flix > 1 + \
.... > 2
works and
flix > \\
.... > 1
.... > +
.... > 2
.... > \\
works.
Another thought I had, the repl can be used instead of the documentation sometimes ("What list is n
in using List.split(n)
?") by just running the function. Python enhances this further by allowing print(str.__doc__)
to see the documentation. I think documentation access would be nice to have in some form.
@stephentetley I seem to remember you were also a fan of REPLs :) I'd also appreciate your input:
It would be nice to run Datalog queries directly (or near directly) in the REPL.
It looks like GHCi allows redefinitions but the new declaration shadows the old one:
I haven't used the new REPL yet. I use VSCode but I seem to be missing the features more powerful than syntax highlighting. My .vscode
doesn't seem to have a flix.jar, but I run with an updated one that tries to track flix/flix head.
I use VSCode but I seem to be missing the features more powerful than syntax highlighting. My .vscode doesn't seem to have a flix.jar, but I run with an updated one that tries to track flix/flix head.
If you place an up to date flix.jar
in the root of your project, the VSCode plugin should use that. You should see something like this in the "Flix Compiler" channel of the "Output" window (it should be displayed automatically when you open a Flix file):
LSP listening on: 'localhost/127.0.0.1:8888'.
Flix 0.28.0 Ready! (Extension: 0.75.0) (Using /Users/paulbutcher/Projects/flix-playground/flix.jar)
Do you see that? And if not, what do you see?
It looks like GHCi allows redefinitions but the new declaration shadows the old one:
Do you use this "redefine but shadow" functionality? It sounds to me that it adds quite a lot of complexity (both in terms of the code, and also in the user's mental model) which we should only contemplate if there's a strong reason to do so?
Do you see that? And if not, what do you see?
Thanks @paulbutcher - yes this works.
It would be nice to have a setting for compiler path in the Flix VSCode extension then I don't need a copy of the jar in each of my projects.
Do you use this "redefine but shadow" functionality?
No, my own GHCi "workflow" is quite primitive - I have a Haskell source file where I write any declarations or function definitions and I load and reload that. At the prompt I almost always just invoke functions I've written in my "doodle" file.
Thanks @paulbutcher - yes this works.
Good to hear. What happens when you don't have flix.jar
in the root?
It would be nice to have a setting for compiler path in the Flix VSCode extension then I don't need a copy of the jar in each of my projects.
Understood. One of the things I'm planning on looking at soon, I hope, is packaging, which will consider all of:
But I want to get the Java interop and REPL workflow working first 😜
Good to hear. What happens when you don't have flix.jar in the root?
I think it should delegate to one in .vscode
user configuration. For some reason VSCode doesn't download a flix.jar
for me on Windows (I've seen it does on Linux).
How to determine which Java libraries to use How to determine which Flix libraries to use
A simple scheme would be to follow Flix package manager which is working very well for me. Look for libraries - jars and Flix .pkg files - in a lib
folder at the top level of the working directory.
Magnus asked me to put together some thoughts on what I would expect from (and just as importantly, what I would not expect from) a Flix REPL. To my mind, there are two key use cases that a Flix REPL should enable:
What is definitely out of scope, I think, is:
Possible User Experience
Note: What follows are concrete examples of one possible approach to stimulate discussion. Everything is up for discussion!
User starts the REPL within an existing Flix project:
The
User>
prompt indicates that they’re in the defaultUser
namespace.Note: We might choose to support running the Flix REPL without an existing Flix project, but I don’t think that that’s high priority.
Note: We might choose to allow users to define their own prelude for the
User
namespace (for example within~/.flix/
) in which they can define common helper functions they find useful during REPL sessions.User explores the Flix language, e.g., trying out a few simple expressions:
Note: there are all kinds of different naming schemes we could use to allow the user to refer back to intermediate results, and ways to indicate them visually (e.g. different colours etc.). Some REPLs use positional references (e.g., $1 to refer to the most recent result, $2 the previous one, etc.). My preference would definitely be for named intermediate results.
User explores defining functions, enums, etc…
Note: the REPL will need to be able to parse “enough” of the input to know whether or not it should display the
...>
continuation prompt.More exploration:
(Most of) normal Flix semantics and rules hold. So, for example, redefining a name that already exists is an error:
The obvious exception to the above is that Flix’s rules about unused variables will have to be disabled within the REPL.
The user can refer to anything defined within the project (e.g. calling functions, using types, etc):
It should also be possible to run the program within the background, and then examine its state as its running. For example imagine that our program is a web service (not possible yet, but hopefully soon!):
Then later, after the server has serviced some requests:
Note: the VSStudio plugin should support a window containing the REPL, and provide a “run and open a REPL on the running program” option.
Once we’ve debugged our problem (whatever it is) we edit the source code of the project and rerun.
Note: no changing the running program in place.
Note: it will be possible to change the state of the running program by calling side-effecting functions.
Note: we'll need to consider side-effects in the implementation, which disallows a "collect everything the user's typed at the
User>
prompt into a function and rerun every time" approach.