« first day (386 days earlier)      last day (1682 days later) » 

3:05 AM
@DLosc I made a pullrequest just now that does a couple of things. First, it creates a symlink to appleseed.py called appleseed, since Unix programs generally don't have extensions. Second, I marked appleseed.py as executable, so it can be called ./appleseed instead of python3 appleseed. Third, I changed #!/usr/bin/python3 to #!/usr/bin/env python3, which is more standard.
Fourth, I made it so the repl starts only if the input is a terminal, rather than a process or file. This way, you can do echo 'appleseed_code_here' | ./appleseed and have it execute normally rather than via repl.
 
@Pavel Neat, thanks! I'll probably have to do some serious merging because I'm about to make a massive commit that splits the interpreter into nine files...
Not sure if the best approach is to merge the pull request first and then add my changes locally, or commit my changes and then merge the pull request... I've only done this once before.
 
Well, it'll be much easier to work with in future.
@DLosc Why don't you take a look at files changed? The change is very small, you should be able to decide where to stick it.
 
3:26 AM
I think it's gonna be better to merge the pull request first and then redo my local changes on top of it. Easier than modifying the pull request to make sense with the new code structure.
(Also, that reminds me, I need to update the readme too.)
 
Ok, cool
 
Ughh, too much git terminology is making my head spin. Head branch, base branch, feature branch, default branch, topic branch... and I think all those terms are only referring to two different branches, but it's very confusing.
@Pavel Merged. Now let's see what happens when I fetch the changes locally.
 
Ok
@DLosc I gave up long ago trying to understand. I just merge and fix conflicts.
 
Ha. :)
I guess my two options are 1) commit my local changes and then merge changes, or 2) move my locally changed files elsewhere, fast-forward local master, and re-make local changes over top of your changes. #2 sounds easier in this particular case.
 
4:16 AM
@Pavel The problem with reading program code from stdin is that it creates issues when the program uses stdin for user input. (I realize that isn't a possibility in the Appleseed version you modified, but it is after my local changes.) After sys.stdin.read(), input() gives EOFError. I'm googling for a good solution, but do you have any ideas perchance?
 
@DLosc If code is stdin, then you can change user input to be read from the terminal rather than stdin. On Unix, that's /dev/tty. I'm trying to find how to do it from Windows right now
 
@Pavel This says open("CON") should work. I was hoping for a platform-agnostic method, though.
 
I was about to say conIN$
@DLosc Sorry. You'll have to use either CON (or conIN$) or /dev/tty ddepending on OS
You could have a global variable called INPUT, and set it to either sys.stdin or open("CON", 'r'), or open("/dev/tty", 'r') depending on the conditions set
Also note: Not all systems have a /dev/tty. TIO doesn't run from a terminal, so just let it EOFError and default back to sys.stdin if open("/dev/tty", 'r') causes an error
 
I thought I had something similar working in my Pip interpreter, but it turns out my approach there doesn't work with redirected files as input, just with a terminal user entering manual EOFs. :(
@Pavel TIO will always use the ./appleseed filename approach rather than redirecting or piping the code in, won't it? (I hope...)
 
@DLosc Not if I write a bash wrapper
 
4:28 AM
Well then don't do that! X^D
 
Of course, you could just do what python does, and just say you can't pipe in code that takes input:
$ echo 'input()' | python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
EOFError: EOF when reading a line
 
That's probably what's going to happen.
Oh--I mean ^ if a terminal can't be opened. If it can be, then no problem.
 
Cool
 
5:09 AM
Huge changes committed and pushed. I should probably commit more often. :P
 
Commiting often is a good habit
 
The big news, besides the code reorganization, is that a rudimentary event loop is now in place, which means Appleseed can do (very basic) I/O!
 
\o/
 
And that means that I can ask Dennis to put it on TIO.
Then I can go back, update the readme, try to do something with the bloat that is the REPL help text, and maybe start some documentation.
 
in talk.tryitonline.net, 2 hours ago, by Pavel
@Dennis Can you add Appleseed? HW is "Hello, World!"
 
5:14 AM
@Pavel Haha! Thanks. But I'll have to give him the updated Hello World program.
 
Ah
@DLosc If you do pass, you might find yourself with random RuntimeError: lost sys.stdin. Instead, save sys.stdin in a variable, and if setting sys.stdin fails, set it back to the old sys.stdin.
@DLosc You can also change the function that reads input to catch EOFError and return nil on EOF, which is both more graceful and more useful.
 
@user202729 Re: tinylisp's comment--I suppose I could add a builtin, but it would still have to return something, unless I modified the parser. Which I basically decided not to do because that's what Appleseed is for.
 
(what is Appleseed for?)
I mean, just make it quiet. Like how disp and d are currently.
 
@user202729 Appleseed is a new language where I can implement all the ideas I decided not to put into tinylisp. :D
@user202729 True, that's an option. You'd still only be able to use it at top level, unlike a true comment, but it would be somewhat of an improvement. I'll consider it.
@Pavel The way I'm doing I/O is via an event loop: the user's code returns an ask-line! event, and the implementation gets a line of input and calls the receive-line! handler (if it is defined). Not sure what the best behavior on EOF is.
Options: simply not call the handler; call the handler with nil for the line; call the handler with a special EOF value for the line, or an EOF property on the event object...
Raising an exception doesn't seem to be an option because the error doesn't happen while executing Appleseed code.
I think calling the receive-line! handler with some indication that we've hit EOF is the best option, unless a better one presents itself.
 
5:31 AM
C# and C++'s cin say nullptr. C's scanf says empty string.
Python errors, obviously, which isn't useful
 
And empty string isn't too useful because it doesn't distinguish between EOF and a blank line.
 
I think it should be calling the handler with nil, but I'm not as familiar with this kind of system.
Not calling the handler at all is the only bad option of that list though.
 
Yeah.
Let me write up some sample code and see what I like best...
 
Hmm, well, you have to call it with some value anyway, right? Might as well be nil, then decide if you want to set a special property.
 
Another possibility would be to leave the line property unset, and instead set an eof property.
 
5:38 AM
Is unset not nil? I'm pretty sure tinylisp doesn't deal with Python Nones.
 
Events are objects (which are new, which might be confusing). A normal call to receive-line! receives an event like
{(type Event) (name receive-line!) (line `Hello, World!`)}
One option for EOF would be to send an event like
{(type Event) (name receive-line!) (eof 1)}
 
I feel like this will lead to some rather confusing Error: referencing undefined name line
But maybe I'm not quite seeing how this is all implemented
 
Yeah, I really need documentation. :P
Here's my current test file, maybe this will help:
(load library)

(def start!
  (lambda (event)
    (list
      (map print! (1to 5))
      (write! "10 factorial is ")
      (print! (factorial 10))
      (ask-line! "What is your name? "))))

(def receive-line!
  (lambda (event)
    (print! (strcat "Hello, " (get-property event line) "!"))))
start! and receive-line! are event handlers. The start! event is fired once all the defs have been executed.
Event handlers are supposed to return either an action or a list of actions.
 
So when line is unset, what will (get-property event line) return?
I assume it would error for unset properties
But you have to be able to read from one of line or eof safely without it erroring to determine wether there is an eof
 
@Pavel Yes. Error: object does not have property xyz and then returns nil.
There is also a has-property builtin.
But I do agree, having line set to nil is best, regardless of whether there's also an eof property.
Unless line is set to some custom eof object...
But yeah, probably nil.
 
5:46 AM
What could you possibily do with a custom eof object anyway
 
Distinguish it from nil. For example, if later modifications mean that strings are now lists of characters, then suddenly nil == empty string and is a valid, non-error value for line.
(I'm not entirely happy with how strings are implemented at the moment.)
 
Ah
I think that's a problem with nil, actually.
 
Although I also don't particularly like having nil == empty string, so the final solution will probably be different.
 
You should be able to tell the difference between a list that happens to not have any values, and a null value
 
Hm.
 
5:50 AM
So maybe nil should be None and not (), and make nil be a tinylisp literal that evaluates to None.
 
@Pavel A lot of that issue will go away once we get exceptions, since error conditions are the main context where nil means "no value."
 
It's not just for strings. If, in C++, I had a function that normally returned an std::vector<int>, and nullptr if it happened to be empty, that would be extremely stupid.
And if nullptr was implemented as an empty std::vector, that would be phenomenally stupid.
I realize appleseed isn't C++, but my analogy works in pretty much every single language.
 
Yeah, but this is Lisp. ;) Empty list is usually a null pointer for cons-cell-based lists.
 
I've got a book on common lisp I read three years ago, I should pick it back up one of these days.
 
6:00 AM
@DLosc Where are builtin functions defined? The ones written in Python, not defined by the standard library.
 
They're in execution.py. There's a dictionary at the top of the file, and the implementations are member functions of the Program class.
 
Thanks
 
I couldn't think of really good names for all my files, which is why we have run.py and execution.py. :P
Maybe program_state.py would've been better for the latter.
Except that the Program class does do most of the work, not just storing state.
Also: any thoughts on a better filename extension? The current .asl is from when I was going to call it Appleseed Lisp--doesn't make much sense now that it's just Appleseed. I collected some ideas from TNB the other day, but the more the merrier.
 
6:23 AM
Did you mean to post here?
 
@DLosc I did
.apl would be great if APL didn't exist
 
Yep. Oh well.
 
@DLosc .cydr?
 
I was thinking .seed
 
@Pavel (Adám has been stealing all the good apple-related puns, too. X^D)
 
6:25 AM
@Pavel rip anyone using fractal generators or golly
 
@DLosc TBF, I stole the APL Orchard pun
 
6:45 AM
@Pavel In reply to your now-deleted post: Python extensions don't need to be handled in the event loop, they can have their own macro similar to load. I was thinking of use, although not exactly for what you had in mind, I think. My idea was to have other non-functional stuff in "extensions" that comprise Python and Appleseed components, so that (use file-io) lets you use events relating to file I/O.
 
@DLosc So you can write Python extensions for Appleseed in the same way you can write C extenstions for Python?
 
... Probably? I'm not really familiar with how C extensions for Python work, only that it's possible.
What I had in mind wasn't a full extensibility (if that's a word), just for the event stuff. The functional core of the language wouldn't be extensible with new builtins.
 
Bassically, you write C, but it's C that operates specifically on PythonObjects defined in python.h
It can't be run standalone as a C library or executable
 
@Pavel Uhh... TL;DR. But the concept makes sense.
 
@DLosc "extensibility" is a word, but a better way to use it would be "wasn't full extensibility"
 
7:00 AM
All right, I'm calling it a night. o/
 
same actually, \o
 
 
15 hours later…
10:05 PM
First PPCG answer! \o/
0
A: Print all integers

DLoscAppleseed, 41 bytes (def I(q(((n 0))(cons n(I(sub(less? n 1)n Defines a function I that takes no arguments and returns an infinite list of integers, starting (0 1 -1 2 -2 ...). Try it online! Note: Appleseed is in the early stages of development at the moment, so if this code stops working at...

Syntax highlighting with <!-- language: lang-lisp --> looks like it works pretty well, at least for distinguishing comments from code.
 
 
1 hour later…
11:36 PM
@DLosc I see it automatically closes open parenthesies. May I suggest that, when it does so, it emits a warning to discourage that style in nontrivial codebases.
 

« first day (386 days earlier)      last day (1682 days later) »