9 ms·
Beating the Arc Challenge in Haskell
- parenthesis 17y agoHaskell is that rare beast: a language that Lispers may envy.
- chriseidhof 17y agoI, as a Haskeller, envy Lispers as well. Metaprogramming is so incredibly easy in Lisp. Oftentimes I can find good solutions in Haskell for things that people would normally do using metaprogramming, but still. And almost always the types really help me, but every now and then they get in the way.
- camccann 17y agoAll I really want in a language is something similar to Haskell, with Lisp-like metaprogramming, easy support for Erlang-style concurrency, and syntax that doesn't immediately terrify the Blub programmers. Is that so much to ask?
- fauigerzigerk 17y agoYes I think that is too much to ask. Metaprogramming, I think, is by definition incompatible with compile time type checking. The "meta" in Metaprogramming means that the program is able to manipulate itself (recursively) at runtime. I believe it's theoretically impossible to combine that with AOT type checking and Haskell without its type system would not be Haskell at all. [edit] Of course you could argue that the sort of thing C++ does with templates is metaprogramming as well, only at compile time. In that case I suggest that we need another term for that because it's totally unlikle what Lisp is so good at.
- ericb 17y agoThe post above doesn't mention compile time type checking. Are you implying that to support one of the features he asks for that it is required?
- camccann 17y agoOne of Haskell's defining features is a very expressive and powerful static type system, so yeah, compile-time type inference/checking was pretty heavily implied by "similar to Haskell". And yes, the fact that I was essentially asking for a language with both static typing and runtime self-modification was the reason for the tongue-in-cheek "is that so much to ask". Might as well ask for a program that can compile any legal perl program [0]. That said, I suspect there's a lot that could be done to allow certain subsets of metaprogramming techniques in a static-typed language; some sort of crazy meta-type system that lets the compiler prove that something will only produce code with a particular polymorphic type, maybe? I don't know. [0] EDIT: My bad, it's actually parsing perl that's impossible, cf. http://www.perlmonks.org/?node_id=663393 http://www.perlmonks.org/?node_id=663393
- chriseidhof 17y agoYes. A lot of the meta-programming is actually programming over the structure. For example, given a Java class, you could generate database code. In Java, this relies heavily on introspection, but you if you're interested in doing this in a type-safe way then you could look at Generic Programming (in Haskell). Also, you can generate code (at runtime) which is type-safe, compile the code, etc. Everything you ask for is possible in Haskell, however, it is definitely more complicated than in Lisp.
- fauigerzigerk 17y agoCompiling code at runtime may improve performance, but it doesn't give the kind of guarantees that static typing gives you. Static type checking proves that certain invariants hold at runtime and hence that certain defects are not possible. If a program can manipulate itself at runtime in arbitrary ways (not just reflect on itself in a read-only fashion), those proofs become invalid.
- andrewcooke 17y agoyou might want to google "staged programming" - it's what strongly typed languages do to get metaprogramming. (edit: afaik it doesn't allow the full "recursive manipulation" you describe, but it does let you generate code with code)
- Hexstream 17y agoThank you so much! I've had informal ideas quite like this from working on my "HTML rewriting system" part of my (unreleased) Common Lisp web framework. I now have a very specific search term to acquire more formalized knowledge which should speed up some future developments a lot because I won't have to independently come up with solutions to as many of the problems now.
- andrewcooke 17y agoheh. no problem. if you're interested in this kind of thing check out http://lambda-the-ultimate.com http://lambda-the-ultimate.com from time to time. just skimming the conversations can keep you up to date...
- mainland 17y agoIt's certainly possible for a typed language like ML or Haskell to support metaprogramming. As other have noted, Haskell has Template Haskell. However, systems like MetaML and MetaOCaml support metaprogramming and give much stronger typing guarantees than Template Haskell. See http://www.metaocaml.org/examples/ http://www.metaocaml.org/examples/ for inspiration.
- fauigerzigerk 17y agoSure, but there are theoretical limits to what runtime metprogramming can do whilst upholding the guarantees that a static type system provides. For instance, in order to check that a particular function call conforms to the function signature, the function signature must at least exist. Type checking a call to a function for which not even the signature exists anwhere within the system is impossible.
- astine 17y agoA large part of what constitutes lisp-style metaprogramming is macros, which are definitely a compile-time feature.
- fauigerzigerk 17y agoThat's a very valid point. So I think we have these two types of metaprogramming, the runtime type and the compile time type. The latter is compatible with static typing but the former clearly is not.
- derefr 17y agoIf the compiler is part of the runtime (i.e. an interpreter that compiles expressions in order to evaluate them), and then the type checker is part of the compiler, even eval should be able to throw type errors. What, then, is the problem?
- baguasquirrel 17y agoIt's not a statically typed language like Haskell anymore?
- fauigerzigerk 17y agoThe problem is that the type error occurs at runtime, which is exactly what static type checking is supposed to prevent in the first place.
- derefr 17y agoIt depends on what you mean by "runtime." If you're creating a new datatype, is that really "at runtime," or are you just talking to the compiler interactively? To put it another way: metaprogramming might have effects at runtime, but not the kind of effects that change depending on what the runtime does. Metaprogramming should be deterministic for your program to be considered to be "in production."
- messel 17y agoIf I create syntax with a program (code with code) is that metaprogramming? Doesn't c++ or any text generating code already do this? Maybe it's not "native" and I have to run system level calls to force compiles and execution of created code. Almost all programs do metaprogramming (interpreted code, scala on the jvm, etc). What's the differentiatior for Lisps Metaprogramming (self contained languange structures?). I'm pretty interested in simplification of programmer interfaces on iteratively more functional (but perhaps more complex) underbellies. I will certainly investigate.
- fauigerzigerk 17y agoMy definition of metaprogramming is writing a program that manipulates itself. I'm not sure I would call any arbitrary code generator metaprogramming as this would cause the "self" in my definition suffer a severe identity crisis :-) But yes, C++ templates as well as Lisp macros are compile time metaprogramming. All languages that have eval and/or allow function/method bindings to be replaced at runtime allow runtime metaprogramming. Since static typing guarantees certain invariants it cannot be compatible with a program that violates those invariants at runtime. You could still decide to consider it metaprogramming when the program manipulates itself only within the limits of those guarantees, but when you look at what real world runtime metaprogramming is being used for (for instance in Rails) you will realise that these things (e.g method_missing) would not be possible within the limits of a statically typed language. [edit] Lisp makes both compile time and runtime metaprogramming exceptionally easy due to its homoiconic nature.
- lsb 17y agoLisp-like metaprogramming is really tricky, because a lot of the language that you interact with is defined by macros. The Haskell that you see is a thick layer of syntactic sugar over a much smaller Haskell core.
- gruseom 17y agoLisp-like metaprogramming is really tricky Whoa. That doesn't match my experience at all. I'd say it's simple and practically effortless (compared to what you'd have to do elsewhere). It would be surprising if it weren't, given that the whole language is organized around code=data.
- yummyfajitas 17y agoHaskell has message passing concurrency within a single (OS) process. It's not quite erlang-style concurrency, but it gives you a lot of it. http://cvs.haskell.org/Hugs/pages/libraries/base/Control-Concurrent-Chan.html http://cvs.haskell.org/Hugs/pages/libraries/base/Control-Con... If someone built an AMQP library for haskell, we'd probably be 90% of the way there.
- messel 17y agoAll I want is a language which can tap directly in to my imagination and rapidly create machine functionality and simulations.
- tumult 17y agoYou should check out the Qi language, though the developer who has historically contributed the most to it has departed some months ago. It has the ideas you are looking for (sans message-passing concurrency, I think.)
- pg 17y agoMetaprogramming and syntax don't go that well together. If you're going to manipulate programs effectively, you're going to be operating on source trees, and it's easiest to do that when source code and source tree are of the same form.
- camccann 17y agoThank you for picking up on that half of my joke. Everyone else went for the type system part... Not that it isn't easy to make a candied Lisp dialect with "friendly" syntax more appealing to non-Lisp programmers, but anyone who actually learns a Lisp quickly realizes that it just gets in the way... If I were to personally try creating an "ideal language" to match my tongue-in-cheek plea, I'd probably start with a terse Lisp-like syntax and a HM-like type system and go from there.
- Ralith 17y agoCouldn't you obtain most of that within a Lisp library?
- samstokes 17y agoDoes Template Haskell affect this discussion at all? (That's not a rhetorical question - I haven't tried any Template Haskell, so I'm genuinely interested to know what it's capable of and how it compares to Lisp macros.)
- gwern 17y agoTH does a lot of the same stuff. On a practical level, it isn't as good, though. The implementation leaves a lot to be desired. For example, I once tried to use TH to check XMonad configurations at compile-times (specifically, that their keymaps were sensible), but turns out TH cannot operate on anything defined in the same module! See http://www.haskell.org/pipermail/xmonad/2008-November/006723.html http://www.haskell.org/pipermail/xmonad/2008-November/006723... (if you don't like context, scroll down to 'I had to admit failure').
- gradschool 17y agoCan you give an example of a situation where Haskell type checking gets in your way? Not to take issue, but because I'm a collector. I've been told that it's not that easy to make a list of functions in Haskell unless they all have the same input and output types, which seems restrictive to me.
- jpr 17y agoWell, polymorphic lists are one thing that are somewhat awkward. Other thing is that a small change in some part of program (say introducing an additional parameter, or having to use IO or state) can require massive changes in rest of the program, or a PhD in category-theory.
- tel 17y agoIt's not "easy" to make a list, but instead maybe you would be able to work with a tuple (which is easy). More practically, Haskell is going to ask you implicitly why you want a heterogenous list of functions. In all likelihood they're going to have a common interface at some point and you abstract around that so that the list is still "homogenous" (which is harder, but still pretty easy).
- albertcardona 17y agoAnd a language that is more and more usable for non-pure math tasks.
- jganetsk 17y agoIsn't this problematic? Lispers fling around lots of superlatives, as if their favorite language will never be dethroned from its position atop the language kingdom. And they always felt justified about this. Shouldn't we confront them about this? I do think there's a science of programming languages which can inform us how to best design the tools we use. Isn't it just possible that these Hindley-Milner languages are the next step in the progression that LISP started? Look at the transition from Newtonian to Einsteinian mechanics. They were both great at the time of release, but one is clearly a step forward. The former is usually embeddable within the latter, but edge cases in the former don't quite work the same in the latter. And some cases in the former are just downright illegal in the latter. And unfortunately, the latter is a lot more complex for the power users. But, the latter is more expressive, teaches us more about the world... and enables completely new possibilities like nuclear fusion/fission. This is like the difference between dynamic and static typing. Dynamic typing is certainly embeddable within Haskell. Just define a data type Dyn which is the sum of types Int, String, Float, [Dyn], and Dyn -> Dyn. You will see how much LISP is possible without much added syntactic cruft. But Haskell users don't need and want to operate in this way, because they can leverage the benefits of static typing. Remember, these things don't come from whims of clever people or corporations. LISP and Haskell both come from research of very fundamental ideas. his is much more like real science than social science. And we should keep our eyes open to the future of this field, instead of proclaiming that we're finally done with our "100 year language".
- silentbicycle 17y agoThere isn't some unified continuum of power in languages, though. There are some problems for which a H-M-ish type system is a tremendous advantage, and there are others for which it gets in the way. Same with lazy evaluation - it can make a problem much simpler or much harder to reason about. Sometimes using a language built from the ground up to support distributed and concurrent programming (e.g. Erlang), unification and backtracking (Prolog), or constraint programming is the right tool for the job. Sometimes being able to work close to the Unix kernel or run on an embedded system without an OS is more important. Languages are a means to an end -- they help manage complexity while solving a problem. There's value in being able to extend a language's semantics to support a superset of several major language families, but unless handled very carefully, it can turn the host language into a sprawling mess in the process.
- albertcardona 17y agoI am trying to run the haskell code in Ubuntu 9.10 with ghc6, but: Failed to load interface for `Control.Applicative.Error': locations searched: Control/Applicative/Error.hi Control/Applicative/Error.hi-boot Which library am I missing? apt-file search for Control/Applicative/Error.hi yielded none. Help appreciated from all HN-reading haskell'ers.
- chriseidhof 17y agodo a "cabal install applicative-extras", that should help.
- chriseidhof 17y agoBy the way, I would be really interested in Arc's solution to the second program I've shown.
- KirinDave 17y agoI'm not sure haskell won here. I think maybe programming with monads won. No, really. Web programming and continuation monads seem to have really it it off together. When you add them to another language, you get similar results (e.g., http://intensivesystems.net/tutorials/web_sessions.html http://intensivesystems.net/tutorials/web_sessions.html).
- panic 17y agoI'd be interested to hear if anyone has solved the problem of embedding a series of pages inside of another (in the sense of Seaside) in a pure functional way. In other words, here's my challenge: write http://www.seaside.st/about/examples/multicounter http://www.seaside.st/about/examples/multicounter using the same monadic style.
- nostrademons 17y agoFor pure shortness, I think HTML + JavaScript won here: http://arclanguage.org/item?id=979 http://arclanguage.org/item?id=979 The Haskell example is interesting, though, because it shows a working webapp in Haskell, and it's not even that scary.
- KirinDave 17y agoExcept that these two code examples do two very different things. The Haskell version actually uses a continuation to run multiple requests The Javascript version modifies local mutable state. The Haskell version does it via server interaction, which makes it much more useful to modern web apps.
- gruseom 17y agoVery nice work, and the code is clear and beautiful to a Haskell illiterate such as myself. But I have a problem. If your solution involves writing a library and importing it, have you really written a program with "only 13 nodes total"? If the answer is yes, then why can't I just put that program into a library, call it from a new program with only 1 or 2 nodes, and say "look at the size of this!"? It's not obvious what counts as "the language" and what as "a library". Is printf part of C? I suppose one could argue that if a library is general enough to make an entire class of programs shorter, as opposed to a few specific programs, then it gets to count as "the language". But that doesn't resolve the question so much as reword it. Anyway, this is probably more of an objection to the original challenge than it is to this lovely Haskell code.
- wheels 17y agoYes, I had the same problem with the initial challenge. I could patch virtually and programming language implementation such that it would be possible to write a 5 line web app, but that doesn't really say much about the language.
- jrockway 17y agoBut Arc itself is is exactly this "patch of a programming language implementation". Also, everything in programming could be much less concise if you wanted it to be. Consider addition. It's an operator in your language. Then it's a CPU instruction. Then it's bits going through logic gates. Since it's a common thing to use, the complexity is abstracted away in many places. If you are writing web apps, it makes sense for your web app libraries to abstract the web stuff away like this too.
- DanielBMarkham 17y agoI have had the same problem with the challenge as the gp ever since I read it. I'm a bit perplexed at what exactly Paul's point was. So I write a templating module for OCaml that lets me beat or tie the Arc challenge. I compile it and never have to look at it again. It becomes part of my toolkit. What do I have to do in order to win the challenge? Get my module accepted into some standard library? Why would what some language committee decides be important in terms of how expressive the language is? It doesn't make sense to me. All it shows is that Paul controls Arc and has configured it to deliver small answers to questions that he finds important. I'm not sure it says anything about Arc or any other language for that matter. It might say something about functional versus imperative languages, but perhaps we already knew that?
- JulianMorrison 17y agoI truly don't get what this is trying to demonstrate? I mean, I could write a one word web app: dwim (Details of the standard library implementation are left as an exercise.)
- anc2020 17y agoI'm a bit late here, but if you want to really smash the challenge, you can use Lisp style metaprogramming with my Hasp program. Something like this is possible (10 nodes): def arc with->>= name input link "click here" display++ "you said: " name
- deleted 17y ago[deleted]