Earlier quoted context omitted.
I would definitely watch a video series in which an experienced and talented programmer tried out various programming languages for an hour and gave first impressions, comparisons, etc as they hacked something together during the video.
The idea of a twitch.tv stream sounds interesting, with viewers throwing small problems at the coder to solve as they fumble around with a new language.
A Haskell Programmer Tries to Learn Racket
91–100 of 163 posts
Re: A Haskell Programmer Tries to Learn Racket
#92Re: A Haskell Programmer Tries to Learn Racket
#93As others have said, this does justice to the idea of actually learning a new language...or perhaps because it is Racket a new family or ecosystem of languages. Anyway, if you're still curious about pairs verus lists and why anyone would use dotted pairs, I like to think about it as where Lisps show that they are from the age when running close to the metal was a given. And it all goes back to car and cdr and the fac…
My question is, given the cons pair is not a meaningful primitive datatype to modern CPUs (can't fit in a register unless you're using 32 bit atoms on a 64 bit CPU, the individual cells cannot be meaningfully manipulated while packed into a single register even in that case...), is there a good reason to use an unrestricted pair/2-tuple/2 element vector for the sexp representation? Would it be "wrong" to remove dotte…
cons is useful for dealing with linked memory structures, including singlely linked lists and particularly singly linked lists where the stored value in each list element is a pointer because it abstracts over all the pointers. Writing code to process and manipulate and pass pointers is idiomatic in C. Using pointers is idiomatic Lisp.
Your barfing code shows why cdr and car persist. They are also powerful abstractions due to their rules of combination and probably because their rules of combination aren't constrained by a bias toward English language. There ain't no synonyms for "caddr" and "cdddr" in English or Python.
The idea that lists should be everywhere replaced by structs is assembly in any language thinking (also known as C). Lists provide a standard interface. Each struct definition creates a new data type.
It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures. Alan J. Perlis, Epigram 9.
Re: A Haskell Programmer Tries to Learn Racket
#94Earlier quoted context omitted.
I find DrRacket sufficiently fast and sufficiently frustrating. It's very useful for interactive debugging but dependent on the mouse and many Emacs key combinations simply cannot be mapped because of it's CUA interface...and so far as I can tell there is no key-combination that switches focus between the REPL pane and the Editor pane short of closing the other pane. The syntax analysis gets to be a bit much too. On…
I think you can switch panes with C-x C-o, same as the Emacs combo.
Re: A Haskell Programmer Tries to Learn Racket
#95Earlier quoted context omitted.
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…
To me, "almost completely compatible" sounds similar to "just a tiny bit pregnant". In practice, either it is compatible, or it isn't.
Re: A Haskell Programmer Tries to Learn Racket
#96A friend of a friend has considerably code in Scheme, Common Lisp and Clojure, when you ask him which is the true Lisp, guess what will he answer? Haskell! Haskell does really create a big impact on some developers. Just an anecdote ;)
I think it can't be "the true Lisp" without cleaner macros. Of course, that doesn't stop Haskell from being a great Haskell.
I suppose that makes Lisp the Principia Mathematica.
Re: A Haskell Programmer Tries to Learn Racket
#97Earlier quoted context omitted.
I probably shouldn't have focused on data structures when talking about dotted pairs, but some days it's just hard to be a Lisp head... > (define (f g) ((car g)(cdr g))) > (define my-val (cons sqrt 4)) > (f my-val) 4 ...and go down the rabbit hole where code and data merge.
As another Haskeller... f :: (a -> b, a) -> b -- a.k.a. `ap` f (a, b) = a b myVal :: (Double -> Double, Double) myVal = (sqrt, 4) > f myVal 2 -- I hope In other words, what's different about (a . b) and (a, b)? But then: why not (a, b, c)?
(define side-effect (cons print "This is not an IO monad"))
(define its-already-generic (cons number->string 4))
The more I think about Lisp the more I believe that the best reference language is C. [1] Lisp took form as a first step away from assembly, not a first step toward the singularity. What is garbage collection but some lazy programner automating memory management?The mistake is to take the ideological fanaticism of Lispheads for ideological purity of the language. There is none. Even the great schism of Lisp1 versus Lisp is rooted largely in arguments from precedent...and precedent for Lisp is largely that it can shave a few precious bytes and register loads by allowing a single symbol to point to more things.
[1] Or Cobol.
Re: A Haskell Programmer Tries to Learn Racket
#98Earlier 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…
> I'm just confused as to why anyone is particularly impressed with Node or JS. Low barrier to entry means anyone who used to animate jumping monkeys on webpages and now write distributed back-end systems (all web-scale of course). Kids haven't seen anything else. Maybe took C++ or Java in college, then they see a kid with piercings and a messenger bag and tight pants talk about this awesome asynchronous callback-fut…
There is nothing distributed about Node. It has IO concurrency, that is all.
Re: A Haskell Programmer Tries to Learn Racket
#99Earlier quoted context omitted.
> 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 buildin…
Time for experiment. SBCL doesn't, as far as I know. But you seem to imply that it is always better to use hash-tables, and I don't think so (even though hash-table can be implemented in a smart way, like in Lua).
Under roughly 10 elements, alist result in shorter code.
(defun my-fun (x)
(declare (optimize (speed 3) (debug 3) (safety 0))
(type (member a b c) x))
(let ((a '((a . 10) (b . 21) (c . 31))))
(cdr (assoc x a :test #'eq))))
(disassemble #'my-fun)
; disassembly for MY-FUN
; Size: 53 bytes
; 04A7FF2F: 483B1592FFFFFF CMP RDX, [RIP-110] ; 'A
; no-arg-parsing entry point
; 36: 7511 JNE L1
; 38: 488B0D91FFFFFF MOV RCX, [RIP-111] ; '(A . 10)
; 3F: L0: 488B5101 MOV RDX, [RCX+1]
; 43: 488BE5 MOV RSP, RBP
; 46: F8 CLC
; 47: 5D POP RBP
; 48: C3 RET
; 49: L1: 488B1D98FFFFFF MOV RBX, [RIP-104] ; '(B . 21)
; 50: 488B0D89FFFFFF MOV RCX, [RIP-119] ; '(C . 31)
; 57: 483B157AFFFFFF CMP RDX, [RIP-134] ; 'B
; 5E: 480F44CB CMOVEQ RCX, RBX
; 62: EBDB JMP L0
This is roughly equivalent to a "case" construct (not shown here). Then, this is what I have with a hash-table: (let ((table (make-hash-table :test #'eq)))
(declare (optimize (speed 3) (debug 3) (safety 0)))
(setf (gethash 'a table) 10)
(setf (gethash 'b table) 21)
(setf (gethash 'c table) 31)
(defun my-fun-hash (x)
(declare (optimize (speed 3) (debug 3) (safety 0))
(type (member a b c) x))
(gethash x table)))
(disassemble #'my-fun-hash)
; disassembly for MY-FUN-HASH
; Size: 115 bytes
; 05467EB0: .ENTRY MY-FUN-HASH(X) ; (FUNCTION (#)
; (VALUES T # ..))
; EE8: 8F4508 POP QWORD PTR [RBP+8]
; EEB: 488D65E8 LEA RSP, [RBP-24]
; EEF: 488B7805 MOV RDI, [RAX+5]
; EF3: 4C8BC7 MOV R8, RDI
; EF6: 498BF8 MOV RDI, R8
; EF9: BE17001020 MOV ESI, 537919511
; EFE: 488B05FBFDFFFF MOV RAX, [RIP-517] ; #
; F05: B906000000 MOV ECX, 6
; F0A: FF7508 PUSH QWORD PTR [RBP+8]
; F0D: FF6009 JMP QWORD PTR [RAX+9]
; F10: 6A20 PUSH 32
; F12: B9604F4200 MOV ECX, 4345696 ; alloc_tramp
; F17: FFD1 CALL RCX
; F19: 59 POP RCX
; F1A: 488D490B LEA RCX, [RCX+11]
; F1E: E917FFFFFF JMP #x1005467E3A
The function with an hash-table has a constant size relatively to the number of elements in the table, which is fully known at compile-time. The size of the code with a case/alist grows linearly with the number of elements.Now, let's compare speed.
In the following versions, I have added more elements in the alist, just to be sure the code with an hash-table is the shortest (from 'a to 'l).
(time
(dotimes (i 10000000)
(dolist (x '(a b c d e f g h i j k l))
(my-fun-hash x))))
(time
(dotimes (i 10000000)
(dolist (x '(a b c d e f g h i j k l))
(my-fun-case x))))
(time
(dotimes (i 10000000)
(dolist (x '(a b c d e f g h i j k l))
(my-fun x))))
Results: HASH:
2.491 seconds of real time
33,072 bytes consed
ALIST:
0.852 seconds of real time
0 bytes consed
CASE:
0.778 seconds of real time
0 bytes consed
Even though in terms of footprint, the code tend to be larger with alist quite rapidly (10 elements), the resulting code is faster and does not allocate memory.Also, just to clarify, alist and property lists have a different behavior than hash-tables, namely that the sequential access allows you to shadow values from another list: if you write (cons (cons 'a b) older-alist), you have a new list where the value for key 'a is b, and where values for other keys are those found in older-list (even though older-list also contains key 'a).
I don't quite remember what is my point anyway ;-) but it was fun to test the different behaviors.
Re: A Haskell Programmer Tries to Learn Racket
#100This 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…
On the other hand, such a language might just end up as an incredibly fragmented mess of different languages, with little interoperability between languages - some one makes a 'typed' version of the language, another takes that version and tunes it just enough for it to be incompatible with the original version and, in turn, all languages that are built on top of that original typed language, and so on.
Maybe incredible modularity is fundamentally at odds with (social) interoperability.