Live data from Hacker News

A Haskell Programmer Tries to Learn Racket

artyom.me

71–80 of 163 posts

Re: A Haskell Programmer Tries to Learn Racket

#71

Earlier quoted context omitted.

Try the Geiser plugin for Emacs. It allows you to connect to the Racket REPL (either it starts a new instance of Racket, or it can connect to a socket/port). I'm a Vim user and went through elaborate pains to get Emacs working almost like Vim just so I could go through SICP this way.

Could you please outline your final setup besides using Geiser? I also come from Vim-land, have almost zero experience with Emacs and already understood that, to learn SICP, setting up and learning Emacs is going to be easier than setting up Vim for the task.

Well, I'd suggest if you know nothing about Emacs to install Emacs Prelude: https://github.com/bbatsov/prelude

Next, enable the lisp/scheme modules in prelude-modules.el [1]. You need the Evil plugin to get Vim modal editing and probably Evil Leader (so you get Vim style commands).

You can look at my config [2], there's nothing really funny except I map Ctrl-H to backspace and Ctrl-[ to ESC as that's what I also use in my Vim. There's also a slight modification to make Smartparens make parenthesis highlighting behave like in Vim.

One other thing is if you're in insert mode then Emacs keystrokes should also work (Ctrl-Z to force switching between Vim/Emacs keystrokes).

If you install the SICP plugin for Emacs (it's in my custom.el) and you type M-x info-display-manual sicp, or if you have Evil installed you can use use Vim's command :info-display-manual sicp, you'll get the SICP book as a manual inside Emacs.

[1] https://github.com/humana/dotfiles/blob/master/emacs/prelude... [2] https://github.com/humana/dotfiles/blob/master/emacs/persona...

Re: A Haskell Programmer Tries to Learn Racket

#72
This is how I usually implemented quicksort in Racket:

    (define (quicksort xs)
    (if (null? xs)
    xs
    (let* 
        ([hd (car xs)] 
         [tail (cdr xs)]
         [smaller (filter (lambda (x) (= x hd)) tail)])
      (append (quicksort smaller) (list hd) (quicksort bigger))))
It's great to see a hugely superior implementation, and I love that people are writing about and using Racket like this because the more people do that the more resources there will be for people like me to learn from.

Re: A Haskell Programmer Tries to Learn Racket

#73

Earlier quoted context omitted.

I keep flipping back and forth, thinking I don't get it, then thinking others don't get it. Single-threaded JS with callbacks. OK? What am I missing? The only thing Node has going for it is a lot of networking libraries. It's not fast, the async style leads to callback hell, JS is a terrible language, and their package management system is slow and bloated (or at least the packages are)[1]. Yet people think it's some…

Straight from the horse's mouth: "Node is popular because it allows normal people to do high concurrency servers. It's not the fastest or leanest or even very well put together - but it makes good trade offs in terms of cognitive overhead, simplicity of implementation, and performance. I have a lot of problems with Node myself - but the single event loop per process is not one of them. I think that is a good programm…

> I am not an app programmer arguing what the best platform to use for my website--I'm a systems person attempting to make programming better.

What is a "systems person", in this case? I guess it makes sense if you know who it was who said this, but I don't. Is it a programmer working with code for servers?

Re: A Haskell Programmer Tries to Learn Racket

#74
post #10

One note: > Racket's default IDE is better than GHCi and probably on par with Emacs (you almost certainly can configure Emacs to be better than anything, but it's not trivial and people don't bother, while DrRacket provides autocompletion and documentation out of the box). Last I used it (a few years ago), DrRacket was very laggy, so I would find it very hard to use for a serious project. YMMV, maybe it's improved.

I actually found DrRacket very fast and Emacs very slow, on every computer I've tried them on. Why might this be?

Re: A Haskell Programmer Tries to Learn Racket

#75

Earlier quoted context omitted.

I come from a background using Common Lisp for system and web development so I may see things differently than people who were introduced to it academically. Your code looks great, mine just needed to compile :) The cons pair is a a really powerful primitive data structure, it is the linked list of Lisp. You can build a lot of powerful structures given this great base. I really don't it matters what architecture your…

I mean, it's neat that you can build everything out of cons, in the sense that it's neat that Turing machines and the lambda calculus can perform any computation, but that doesn't mean it's a good idea to so in your code, any more than encoding numbers with Church numerals. Why use alists when you can use hash tables, why use... weird SICP-style struct list things when you could just use structs/vectors, etc. >Hash T…

> but a quick search didn't reveal a syntax for hash table literals, which I would consider to be a prerequisite for calling them first class citizens

http://en.wikipedia.org/wiki/First-class_data_type

Hash-tables are part of the standard, and available in conforming implementations out-of-the-box. (make-hash-table) produces an instance of a table which can be passed as argument to function, be assigned to variables, ... I don't think syntax defines what feature is or isn't first-class, even though it has an impact on it's usage.

Adding support for litteral hash-tables is possible, as it was already said: define a reader macro; that macro could even simply use the utility function "plist-hash-table", from Alexandria, which is used like this:

     (alexandria:plist-hash-table '(:a 1 :b 2))
So that you could write #H{:a 1 :b 2} and get what you want.

On the first hand, people say that CL is bloated, but on the other hand, they want to have everything available by default. Do you expect Python or C++ implementations to come with regular expression built-in, or is it okay if you need to add an 'import' statement or link with Boost?

CL allows you to define libraries that can change even the basic surface syntax, for your convenience. Considering that there is more than enough defined in the specification, what benefits would be in having an "official" hash litteral syntax? consistency accross different projects? many people use the "cl-ppcre" regex library without problem.

Yes, regular expressions come in a library even though they could easily be labelled as a fundamental feature of a language, and hence be expected to be "first-class", or "built-in"; but again, that is not the case in CL, which is neither Perl nor Lua.

And about keyword parameters, this is just the surface syntax, which is on purpose based on a simple, basic representation of the syntax tree as lists of expressions.

Then, the compiler will work with the argument list in your function definition and take one or another approach to represent them in the object code. And I doubt that they are stored in a hash-table, which is unlikely an appropriate way to handle a couple of keyword arguments.

Similarly, when you define a class, everything is declared by a simple list of slots, where slots are lists of parameters: but in fact, the class might store the actual instance slots in a hash-table, an array, a list, a database or a memory mapped file.

The fact that you are mainly manipulating lists does not mean that everything is eventually represented as supposedly inefficient linked-list at runtime.

Re: A Haskell Programmer Tries to Learn Racket

#76
post #61

This sums up quite a lot about Lisps in general. I'm amazed OP got so fast to this "insight" :) (And this is probably Lisp's greatest weakness as well – with this level of possible diversity, everyone has to use the “common lowest denominator” simply because nobody can agree on what alternative syntax / library / etc. is better and should be used.) Off-topic: it's not enough to give everyone opportunity to improve th…

That's very true and I think that it's related to the topic of Rich Hickey's talk Simple Made Easy [1].

Maybe what we need is to study the economics of software and come up with a system in which market outcome is promotion of good libraries. I think that the social/economic dynamics of software development play a huge role in building a successful product, both free and commercial. Has anyone studied the subject in greater detail?

[1] http://www.infoq.com/presentations/Simple-Made-Easy

Re: A Haskell Programmer Tries to Learn Racket

#77

Earlier quoted context omitted.

I mean, it's neat that you can build everything out of cons, in the sense that it's neat that Turing machines and the lambda calculus can perform any computation, but that doesn't mean it's a good idea to so in your code, any more than encoding numbers with Church numerals. Why use alists when you can use hash tables, why use... weird SICP-style struct list things when you could just use structs/vectors, etc. >Hash T…

> but a quick search didn't reveal a syntax for hash table literals, which I would consider to be a prerequisite for calling them first class citizens http://en.wikipedia.org/wiki/First-class_data_type Hash-tables are part of the standard, and available in conforming implementations out-of-the-box. (make-hash-table) produces an instance of a table which can be passed as argument to function, be assigned to variables,…

> http://en.wikipedia.org/wiki/First-class_data_type

Fair enough, pretend I said "first class syntactic object."

> CL allows you to define libraries that can change even the basic surface syntax, for your convenience. Considering that there is more than enough defined in the specification, what benefits would be in having an "official" hash litteral syntax?

Reader macros are powerful, no doubt. The benefit of building this into a language would mainly be syntactic regularity. CL as it stands has keyword args, alists, property lists, and real hash tables (probably amongst other things I don't know about), that all fill basically the same purpose of mapping names to values. If the creators of Common Lisp and its parent lisps had started with hash tables with standard reader syntax, they probably wouldn't have felt the need to introduce so many subtly different but conceptually identical concepts. Lua, for instance, uses its single table data structure both as syntax and as an internal representation for pretty much any case where it needs to map some names to some values; from keyword arguments to environments to "metatables" that provide fairly powerful metaprogramming support, they're all just tables that you can write literally and use the same functions to manipulate. You could say that alists fill this purpose and are even more syntactically regular since they're still sexps, but then why doesn't CL use alists for keyword args, and why don't Scheme's keyword arg extensions use alist syntax? Historical accident, or are alists just ugly? If you can admit that they're a little too ugly and verbose to include in function calls, then maybe you can see why I don't like writing alist literals.

> The fact that you are mainly manipulating lists does not mean that everything is eventually represented as supposedly inefficient linked-list at runtime.

I'm well aware that a compiler can easily expand keyword arguments into regular ones. I strongly doubt your compiler will transform all the literal alists in your program into hash tables, and replace all the alist-ref functions and so on operating on them with the equivalent hash table functions. As long as alists are more syntactically blessed than hash tables, people will use them where another data structure would be more appropriate.

Re: A Haskell Programmer Tries to Learn Racket

#78
post #61

This sums up quite a lot about Lisps in general. I'm amazed OP got so fast to this "insight" :) (And this is probably Lisp's greatest weakness as well – with this level of possible diversity, everyone has to use the “common lowest denominator” simply because nobody can agree on what alternative syntax / library / etc. is better and should be used.) Off-topic: it's not enough to give everyone opportunity to improve th…

As a lisper, I can say that this insight is very true, but it is still just a simplification. Most lisps deal with it in different ways.

In the scheme world, the way they deal with this is by wasting a decade on making decisions about the language that should have been done in the 80s. The result is that scheme essentially split into scheme and racket. Now we have an awesome language and a nice little ecosystem thats good for teaching and research, and possibly even real work(tm). Classic scheme unfortunately is fragmented into implementations who all do things slightly differently and occupy their own niches.

In the clojure world, they have a) a BDFL who sets the course of the language. b) A very strong core community of very smart people who managed to build a nice culture based on common ideas about software and design.

In the common lisp world, because we have a very high-quality standard, implementations are almost completely compatible. Compatibility libraries make it easy to write very portable code, avoiding the scheme problem. At the same time implementations are free to experiment. The other problem of everybody developing their own little universe tends to be rare. Because common lisp is so old, we have a long history and traditions that guide future design, but don't constrict it. There is a subtle balance here. We have a lot of old examples to learn from, but we are not locked in by too many bad old decisions(not always the case, but good enough in practice).

A few examples where this does not work include utility libraries and things like json libraries, libraries for outputing html etc. Since we don't have a BDFL we are left to figure things out amongst our selves and sometimes, like with utility libraries(there are dozens such, which is ridiculus) it doesn't work. In other cases, it works very well, for example quicklisp, ASDF, bordeaux-threads, closer-mop, hunchentoot etc. are either de-facto standards, or sufficiently popular to be a very good default. As with clojure, there are a lot of common ideas about what is good design in the community, we have a lot of examples to learn from, as I mentioned.

In the end, at least in the case of common lisp and clojure, I see it as an advantage to have this "level of possible diversity", it's what has kept lisp alive for 50+ years! The fact that lisp can adopt to each new era of software development philosophy is a great reason to study it. It will be with us for many more decades because of this.

Re: A Haskell Programmer Tries to Learn Racket

#79
post #3

"...but nothing beyond that. As long as Node.js exists in this world, I can't truly hate anything else." I found this hilarious. I am also rather underwhelmed (to be nice) with Nodejs and a little bothered at its wide adoption. I have also been learning racket recently; my formal language and functional programming class uses it. I had some previous experience with common lisp but the raw nature of scheme still pleas…

I keep flipping back and forth, thinking I don't get it, then thinking others don't get it. Single-threaded JS with callbacks. OK? What am I missing? The only thing Node has going for it is a lot of networking libraries. It's not fast, the async style leads to callback hell, JS is a terrible language, and their package management system is slow and bloated (or at least the packages are)[1]. Yet people think it's some…

Javascript is fast enough to be usable on a server, Javascript has grown client-side, and you can share code across both. That adds up to something at least reasonably useful and unique.

Re: A Haskell Programmer Tries to Learn Racket

#80
post #3

"...but nothing beyond that. As long as Node.js exists in this world, I can't truly hate anything else." I found this hilarious. I am also rather underwhelmed (to be nice) with Nodejs and a little bothered at its wide adoption. I have also been learning racket recently; my formal language and functional programming class uses it. I had some previous experience with common lisp but the raw nature of scheme still pleas…

I keep flipping back and forth, thinking I don't get it, then thinking others don't get it. Single-threaded JS with callbacks. OK? What am I missing? The only thing Node has going for it is a lot of networking libraries. It's not fast, the async style leads to callback hell, JS is a terrible language, and their package management system is slow and bloated (or at least the packages are)[1]. Yet people think it's some…

The one good thing about the packaging system is that each dependency is its own version, so you can easily load different versions of the same package.
Post reply on HN