-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move atoms implementation from stepA to step6 #130
Conversation
The Travis build (https://travis-ci.org/kanaka/mal/builds/96677124) is still running, but there are already few implementations that fail on the new step6: cpp, forth, factor, guile, rpython. I'll need to look deeper. |
rpython is just a pre-existing compile failure that happens sporadically (I'm hoping a newer version of the rpython compiler will fix it). I'm not sure about factor and guile yet, but cpp and forth are because swap! is defined as a mal function in stepA rather than natively. Apart from the failures, I think the only thing I would like to see is to clarify that with atoms, they are a reference type and so it's not the value in an atom that changes but rather that the atom switches from referring from one immutable piece of data to referring to another immutable piece of data (identity). It might also be worth referring to http://clojure.org/state which gives an overview of Clojure's approach to state which is basically the same approach in mal. Also, Rich Hickey's "Value of Values" talk is great although might be a bit much to include in the guide. I've been thinking about an adjunct document that has a been of links for each step that point to other resources where people could go for deeper learning about the concepts from that mal step. Just a thought. |
I have a solution for guile (need to port a bit of function wrapping done in step8 earlier to step6 to support the The problem with forth and cpp is that |
Implementing swap! in terms of apply and reset! is perfectly valid, but I think we should re-implement those as native for two reasons: consistency between all the implementations, and I find that implementing swap! natively is really useful in terms of learning because it manipulates and recombines parameters in a way that other functions don't. We could also move apply to step6 too, but it fits well with map (higher order functions) so moving apply and map (even just apply) to step6 feels like maybe a bit too much in step6. Anyways, I could probably be convinced otherwise, but for now I'm leaning towards just making cpp and forth have native swap! functions. On a related note, for being a Scheme (which is known for being a simple well planned variant of Lisp), I keep being surprised by the number of messy little workarounds that are necessary in the guile implementation. Oh well. :-( |
Regarding the atoms discussion, the problem in step6 is that we haven't yet defined any data structure modification functions (cons, conj, assoc), so it's a bit hard to explain the point (again, for people not already familiar with the notion of immutable data structures). Maybe we can use |
Hmm, that's a really good point. The problem with strings is that in many (maybe most) languages, strings are already immutable so it might lose some of the impact. I'm fairly under the weather today so deep thoughts and analysis is probably not going to happen from my end. Do you think this is a serious enough issue to reconsider the direction? We could always have the discussion of immutability in a later step and just allude to it during the implementation of atoms in step6, but that does feel a little bit unsatisfying. Hmmm... |
Maybe spreading the discussion of immutability over several steps wouldn't be such a bad thing. An intro when atoms are introduced, then go a bit more in depth in step8 or step9 as we introduce introduce functions that would be expected to mutate in other languages. Maybe ... still mulling it over. |
(get well soon!) Re native swap!: A native implementation of Re atoms in step6 - I think the direction is OK. Atoms are useful even for an integer counter (the Aside: I'm not sure what are your goals in this project (besides being fun, and the challenge like the |
I have a native C++ I'll make a PR for that later today if you like. |
Thanks @sdt that looks good. @kanaka I'm not sure we have a test-case for
Here from Ruby (notice the different string serialization - probably another issue):
|
@sdt a PR would be great, thanks. @dubek good point about swap! needing to be atomic. Regarding the motivation for the project, you're right that it started out as a fun challenge to implement Lisp in some interesting languages, but it evolved into a learning tool and that's really what I consider the primary goal (I go over a bit of the history and current motivation in the presentation I did for midwest.io last month: https://www.youtube.com/watch?v=lgyOAiRtZGw). And that goal breaks down into two subgoals: learning about Lisp, learning an arbitrary other language (with the second one probably being the primary). Mal as a learning tool manifests in several ways:
And my secret "world domination" goal is to see an implementation of mal in every programming language so it becomes THE rosetta stone for language comparison and learning. Okay, every, will probably never happen unless mal becomes the standard/convention example code/program that new language developers also implement along with their language. But hey, a person can dream .... :-) Some of the above should probably be made into a wiki page. But I'm too tired and fuzzy to do that right now. |
@dubek yeah, we should add a few more swap! tests to catch more cases (I'm sure some impls will break). Can you file a ticket on the string issue? I think there are a couple of other cases where there might be some lingering string issues too although I'm having trouble recalling them right now. |
Should the final argument to Also, in both cases, does the final argument need to be a list/vector? The guide has:
Should |
@kanaka Thanks for the thorough explanations. You should definitely extract this to some manifesto. I'll open separate issues for the edge cases of I'll enhance the atoms description and add references to Clojure's state handling rationale. Then there's work on factor's and forth's swap! impl. (I'm travelling in the next 2 days so will probably be mostly offline.) |
@sdt - My intuition about
So I believe the current implementations are correct (I'll probably add some more tests as part of the current PR just to be sure). |
5c07cff
to
e73b667
Compare
I expanded the atoms description in step 6. Still not fixed: forth, factor Also the diagrams should be modified... |
The guide updates look good. I'll be traveling for the next couple of days so I won't have a chance to update the diagrams, but I may be able to get to it later this week. |
Native |
Fix factor in 9eccf95 . I hope travis will be green on this one... |
The `swap!` implementation calls invoke and eval, and therefore require backporting the implementation of invoke for MalUserFn and MalNativeFn from step9 all the way back to step6.
Copy mal-apply definition from step9 to earlier steps (swap! calls mal-apply).
Rebased branch on top of current master to take the latest matlab/octave changes and assess our situation there. |
Now the only failing impl is matlab in step6. |
Okay, I'll take a look at matlab. Stilll on vacation with limited Internet connectivity so it might be a couple of days before I'm able to merge and push everything. |
Merged with matlab and diagram fixes. Tests currently running: https://travis-ci.org/kanaka/mal/builds/101646135 |
RPython failed for the normal reasons, but everything else passed so looks good. |
Fixups to work with kanaka#130
(following discussion in #126)
Moving atoms from stepA to step6. The
@
reader macro is left as optional in step6. Since atoms are implemented only in types+core+reader, hopefully there's no need to change all the existing implementations. I tested C, D, ruby and python on my machine and they pass the tests.This is not ready for merge, but I'm ready for comments.
Still missing:
guide.md
)