18 ms·
Lisp and Haskell (2015)
- dang 6y agoIf curious see also 2018 https://news.ycombinator.com/item?id=17533341 https://news.ycombinator.com/item?id=17533341
- timonoko 6y agoCommon Lisp could evolve into totally parenthesis-free language. By expanding the "powerfull and versatile" Loop-macro into full powerfullness and versatileness. Unfortunately two parenthessis needed, but you can redefine the language having those by default around every file.
- ashtonkem 6y agoIt was originally supposed to, s-expressions (parenthesis) were supposed to be eventually replaced with m-expressions which were influenced by Algol and FORTRAN (the irony), but reviewers of the paper and the initial implementors of lisp preferred s-expressions, which stuck. That being said, having worked professionally in Lisp, the “un-lispy” macros like Loop are some of the worst parts of that language. They completely violate the otherwise standard-ish syntax of Lisp, are very poorly documented, impossible to memorize, and are really hard to debug despite the otherwise excellent tooling available for top tier implementations like SBCL. It was our standard practice to replace these macros with more verbose but idiomatic lisp whenever possible.
- andi999 6y agohow would an idiomatic loop statement look like?
- sfrank 6y agoLike iterate (https://common-lisp.net/project/iterate/ https://common-lisp.net/project/iterate/)
- bjoli 6y agoIterate is more lispy, and for people that don't like macros transversing the loop body (because the errors you get when something like that goes wrong are hard to debug), something like foof-loop for scheme is pretty nice. I am writing this on neanderthal GPRS internet, so I leave finding documentation for these looping facilities an exercise for the reader.
- deleted 6y ago[deleted]
- timonoko 6y agoJust a jumble of random words. They are especially difficult to non-english speakers, because they are not grammatically correct sentences, but rely on some unknown word-order logic in indo-european languages. Same aplies to list comprehension sentences in Python too.
- andi999 6y agoCan you elaborate? I have difficulties understanding what you mean. Do you really mean an idiomatic loop should be 'a jumble of random words'?
- timonoko 6y agoDifficult to explain cause not an expert, but most languages do not have "list comprehension" by post-description. "New York has rats bigger than a dog" comes to mind. In Finnish you can but the adjective word have same ending or grammatical case as the main word. Without those clues the sentence would be nonsensical.
- shakow 6y ago> but most languages do not have "list comprehension" by post-description. "New York has rats bigger than a dog" comes to mind. « New-York a des rats plus gros que des chiens »
- timonoko 6y agoThat is an indo-european language. Those languages have no grammar or rules. You just string words together and hope it makes sense.
- shakow 6y ago> You just string words together and hope it makes sense. I beg your pardon? Messing the word orders in French or German will definitely mess up the sentence. The German would be something like “Im New York sind Ratten, die größter als Hunden sind”, and moving the words would make the sentence invalid – albeit probably understandable.
- vindarel 6y agoRecipes here: https://lispcookbook.github.io/cl-cookbook/iteration.html https://lispcookbook.github.io/cl-cookbook/iteration.html
- Rerarom 6y ago"Haskell is Lisp's missing M-Expression implementation."
- deleted 6y ago[deleted]
- goto11 6y agoParentheses in Lisp is like significant whitespace in Python: A big stumbling block for people who don't use the language.
- kgwgk 6y agoBut for those who use the language one is a powerful feature and the other a minor annoyance.
- agumonkey 6y agoI don't even remember when parens stopped being an issue. I think my hate relationship toward algol syntax was so strong, sexp were an obvious answer from minute 0.
- iambrj 6y agoOne man's hack is another man's elegance
- Insanity 6y agoThe parens made me reluctant to try lisp. Then, 5ish years ago I decided to "just do it", and now they don't bother me at all. The experience of a beginner is also important though, especially for language adoption, this might be one of the reasons why lisp flavours are not more popular.
- konjin 6y agoA lisp without brackets is no longer a lisp.
- adamkl 6y agoHeck, why not just go one (several?) steps further and just use macros to create a DSL for <insert your favourite language here>? https://aphyr.com/posts/353-rewriting-the-technical-interview https://aphyr.com/posts/353-rewriting-the-technical-intervie...
- StreamBright 6y agoClojure and F# are my two favourite languages and I have similar experience. It is much faster to develop F# code because I can rely on the type system to help me handle all the edge cases, pass in the right things and avoid nulls.
- sidkshatriya 6y agoI've always been curious about F#. Is it true that the F# compiler can be super slow especially on larger codebases? I always wonder: why use F# when you can use OCaml? OCaml has pretty decent third party libraries... (Yes multicore support in F# would be a good reason but apart from that)
- dunefox 6y ago> why use F# when you can use OCaml? I have looked at both without any prior experience in them and OCAML tooling is horrible. Also, with no support for unicode in Ocaml, F# is just much better in this regard - even if it lacks modules, functors, etc.
- sidkshatriya 6y ago> OCAML tooling is horrible This is the old view. In 2020 OCaml tooling, if I may be brave to say so, is excellent. Check out the triumvirate of dune (build), opam (external dependencies) and ocaml-lsp (IDE smarts). P.S. ocaml-lsp uses merlin in the backend (ignore that if you are not familiar with merlin).
- StreamBright 6y agoI just spent 2 hours on this excellent tooling to try to upgrade a package with opam, I finally gave up after read all the Github issues and Stackoverflow, etc.
- dunefox 6y agoI spent two evenings (3 years ago, admittedly) to get the tooling setup so that I could install libraries. I got nowhere and gave up. I'm quite interested in the language but everything else seems to be a dumpsterfire.
- lgessler 6y ago> if your code compiles, it probably works I'm always a little frustrated whenever I see this aphorism perpetuated since I think it gives the impression that a static type system is doing more than it is actually doing. In type systems that are used outside of academia, the main thing your static types are doing is checking whether the shapes of your data and functions all line up. With some small exceptions, that's it: the compiler will tell you if your LEGOs fit together, but not if you've built a knife instead of a fork. I know what this aphorism is getting at, which is that in some domains and circumstances a lot of your bugs are "shape" errors, and it's gratifying when you're writing OCaml or Java and you can, say, refactor without hesitation, knowing the compiler will find even the most unused paths where you need to modify an invocation of your function. But it's been my and others' experience that there are many times where this isn't your most pressing concern, and could in fact be a pretty boring concern that you don't even want to pay the type annotation tax for. (I also think there's something to the idea that a static type system can instill too much confidence and encourage the pursuit of bad abstractions like 18-arg functions that can no longer be effectively reasoned about by an unaided human mind, but that's another topic.)
- bgorman 6y agoIf you use a powerful type system like Ocamls's, your can make many error states unrepresentable. This is basically impossible to do in Java. Moreover, in OCaml it is idiomatic to use type inference everywhere except for interface files, so in practice you almost never annotate types.
- sullyj3 6y agoType systems can encode proofs of properties that you want your data to have. For example, suppose you want to write a function that returns the first element of a list. head :: [a] -> a This is the type of a function "head" that takes a list of values of some arbitrary type a, and returns an a. if you feed this function an empty list, what will it do? You can reason from the type signature that the only thing it possibly can do is crash, since there's no way to produce a value of type a without knowing what a is in advance. head (h:_rest) = h head [] = error "Our function is badly behaved!" To ensure that our function never crashes, we can encode the fact that our list is nonempty in a datatype. data Nonempty a = Nonempty a [a] Ie, a nonempty list must contain a value of type a, and a (possible empty) list of as. Then instead of writing a function that crashes when it receives a nonempty list, we can write a function on nonempty lists that never crashes head :: Nonempty a -> a head (Nonempty x _rest) = x What I'm getting at is that, yes, this is just the "shape" of our data. But you can encode more interesting and valuable properties in that shape than might be apparent at first. There are many other interesting examples of using types to ensure that properties that we want to hold for our values, do in fact hold. Edit: I should probably add that "If it compiles it works" is absolutely not always true. It's more of a community in-joke than an actual belief. But it does turn out to be true surprisingly frequently.
- register 6y agoCompletely superficial and not worth reading.
- deleted 6y ago[deleted]
- skellystudios 6y agoCongratulations! You created a self-describing comment.
- li4ick 6y agoJust like lisp!
- behnamoh 6y agoEvery once in a while, there's a post on front page HN about Haskell and/or Lisp. Sometimes these posts get a lot of traction, but what confuses me is despite the apparent popularity of these languages among developers, still they are seldom used in serious software. I know there are exceptions (esp. with regards to Lisp), but still these languages never come close to other languages such as Java, JS, C, or even Scala.
- thom 6y agoMost tech companies are (quite rightly) in the business of managing imperfections, not achieving perfection.
- sullyj3 6y agoCombination of somewhat high barrier to entry (they're unlike most other languages so experience isn't as transferable), and network effects - those in charge of choosing a technology for a project generally make the subjectively prudent decision to use technology that is already in common use, leaving the less common languages in a catch 22.
- rainsil 6y agoI doubt this explanation really captures the gist of the phenomenon. Many current and upcoming trends (containers/Kubernetes, machine learning and Rust, for instance) have suffered in varying degrees from either of those problems, yet their adoption among companies is ever-increasing. I suspect they suffer from an issue also shared by the likes of cryptocurrencies: they don't have a "killer benefit"; a concise, persuasive reason that using them is a discrete improvement over current practice (like "high-level systems programming!", or "self-driving cars!").
- dunefox 6y ago> still they are seldom used in serious software This is mostly because the majority of software developers only know Java and are averse to learning new languages. Also, companies chose Java at one point and are now taking next to no risks by introducing new languages (not even languages on the JVM). They can also just fire and rehire Java developers because there is a large pool of available developers that they can just plug-n-play, so to speak. They're not interested training people.
- bjoli 6y agoI played around with Hackett (a parenthesised Haskell) quite a lot, and I really enjoyed creating my own syntactic abstractions in a haskell-like language. I find I would rarely reach for macros in Haskell, but that I sometimes would like to. Lisp macros do overlap with what you can achieve with Haskell things like typeclasses, laziness, monads and template Haskell, but the overlap is far from 100%. The author of Hackett has a video about it: https://youtu.be/5QQdI3P7MdY https://youtu.be/5QQdI3P7MdY
- dunefox 6y agoHackett would be pretty much the argument for me to choose Racket - but the development is dead at this point.
- thelazydogsback 6y agoRacket platform dev itself dead, or Racket program dev dead? As for the former, I'm on the email distro and it seems pretty active to me.
- dunefox 6y agoThere's an issue on the Hackett Github page where the dev says he doesn't have any free time to keep developing it. That's where I got it from.
- dunefox 6y agoJust tried the code in SBCL and it definitely gives a compiler warning even without executing the function: This is SBCL 1.5.6, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. * (defun add-text-padding (str &key padding newline) "Add padding to text STR. Every line except for the first one, will be prefixed with PADDING spaces. If NEWLINE is non-NIL, newline character will be prepended to the text making it start on the next line with padding applied to every single line." (let ((str (if newline (concatenate 'string (string #\Newline) str) str))) (with-output-to-string (s) (map 'string (lambda (x) (princ x s) (when (char= x #\Newline) (dotimes (i padding) (princ #\Space s)))) str)))) ; in: DEFUN ADD-TEXT-PADDING ; (MAP 'STRING ; (LAMBDA (X) ; (PRINC X S) ; (WHEN (CHAR= X #\Newline) (DOTIMES (I PADDING) (PRINC #\ S)))) ; STR) ; ; caught WARNING: ; The function (LAMBDA (X) :IN ADD-TEXT-PADDING) called by MAP returns NULL but CHARACTER is expected ; See also: ; The SBCL Manual, Node "Handling of Types" ; ; compilation unit finished ; caught 1 WARNING condition ADD-TEXT-PADDING
- phoe-krk 6y agoNote that this is on SBCL 1.5.6 which is a little bit over a year old at this point; the article is from 2015 so we should pick a properly dated version from https://sourceforge.net/projects/sbcl/files/sbcl/ https://sourceforge.net/projects/sbcl/files/sbcl/ and check there. The Common Lisp implementations and compilers keep on getting better with time and they produce more and more compile-time warnings (especially SBCL).
- dunefox 6y agoI know, I just wanted to make a counterpoint in case somebody is deterred from the article.
- slifin 6y agoIn Clojure it's common to develop your application by building it inside a running system Every REPL form sent recompiles the running program, I don't want that fast loop to be force lagged by the program checking types I'm more than happy for that to happen at edit time, independent of compile time outside of my application process So I heavily encourage using clj-kondo to check for mistakes doing primitive type checking etc To reiterate, I love static analysis but I also need control over how and when it runs, I like it in CI and during editing Otherwise it comprises one of the best things about those old languages, (Smalltalk lisp etc) being able to dev your application by injecting code and recompiling while the app is still running The feedback loop while coding a live image is hard to explain but anything that makes it slower is disastrous for me, I can lose focus so quick When deving Clojure idiomatically partial recompile happens at a much greater frequency than most languages, compile time is very important
- skellystudios 6y agoThat sounds super cool, and I'd quite like to give it a go. I'm not sure if what Haskell has is quite the same, abilities but you can hot-reload modules at runtime in GHCi, and FWIW, I've always found the type checker to be pretty zippy.
- adamkl 6y agoThis is what REPL-based development looks like in practice: https://vimeo.com/230220635 https://vimeo.com/230220635 I agree, its pretty cool, and actually pretty fun.
- higerordermap 6y agoI hear this "code as system is running" a lot. Doesn't it complicate our reasoning about the program as compared to simple text files? I haven't heard the other side of this claim.
- Jtsummers 6y agoYou still have the simple text files, but while you're developing (and perhaps in exceptional circumstances while it's running) you interact with it in a live fashion. But the source code is still there, and the whole thing can be recreated from scratch if you kill the image by loading the code. This lets you do things like (stupid trivial example follows, Common Lisp not Clojure) write a function from inside out in the REPL, then move the code to source: > (+ 1 2) 3 > (let ((x 1)) (+ x 2)) 3 (defun add-two (x) ;; in a source file (+ x 2)) > (add-two 1) ;; after evaluating/compiling the above 3 Imagine that these were more complicated things, like you're using a web API and getting JSON files and parsing them. You can develop it interactively, and as you verify that things are correct, you can migrate them to functions (and add tests to really do the verification part).
- rohithkp 6y agohttps://news.ycombinator.com/item?id=24717285 https://news.ycombinator.com/item?id=24717285
- bachmeier 6y agoThis is not the most impressive piece. Two of the main complaints about "Lisp" are that it's not really a functional language and that there aren't enough libraries/the standard library isn't what it should be. These are specific to Common Lisp. Clojure gives you a functional-first Lisp, access to all Java libraries, and a decent standard library. The Common Lisp standard is very old, even if you look at the date it was finalized (1994), but most components are from a much earlier period than 1994.
- veddox 6y agoThe state of the Common Lisp library ecosystem is probably the saddest thing about the language. As the author says, the inbuilt standard library is hopelessly too small for modern requirements - even basics like string manipulation are only cursorily covered. And most of the third-party libraries out there are single-person projects, out of date, undocumented, or all three... The language itself is still fantastic and, IMO, still superior to most other languages out there. But the lack of decent libraries is a major productivity killer.
- vindarel 6y agoHave another look at https://github.com/CodyReichert/awesome-cl https://github.com/CodyReichert/awesome-cl maybe? There might be more than you think. I know I have regularly discovered great libraries the last years.
- veddox 6y agoOh, hey Vincent :D I was thinking about mentioning that list, actually. Yes, there are libraries around for most common tasks. However, there are three things I'm not satisfied with: 1) I expect common tasks to be covered by the standard library. Third-party libraries are for specialised tasks. 2) There's often three or four mediocre libraries for the a given task instead of one really good one. Of course there are some "default libraries" (alexandria, bordeaux-threads, etc.) but too often you basically need to pick one at random and hope for the best. Best example: GUI libraries. 3) Most libraries are side-projects by individual developers or only have small teams. Which means: poor documentation and (in some cases) frequent breaking changes or random interruptions in development. The lack of documentation is not quite as bad as it sounds, because the source code tends to be highly readable. But still, the lack of polish and especially stability is not exactly trust-inspiring. The CL ANSI standard really needs an overhaul to significantly expand the number of inbuilt functions. The fact that my 1990 edition of CLtL2 still adequately describes any modern CL implementation is a testament to the thoroughness of its language design, but also to the lack of change and expansion in the 30 years since. Alternately, the CL community should develop its own semi-official stdlib - like the R community did with the tidyverse. A single package that you can install via Quicklisp that pulls in a curated list of high-quality libraries, ready for use. The CL standard might not come "batteries included" any time soon, but a "battery expansion pack" would still be a major improvement over "bring your own batteries" ;-)
- borishn 6y agoThe inner lambda should have been a separate function with a test :)
- lbj 6y agoI agree with the point on CL libraries, which is truly sad after this many years. But Lisps like Clojure address this formidably by integrating deeply with the JVM and actually also Python. Im not sure his code is idiomatic SBCL but it could be written more succintly and functionally by most LISPers. To the point on static/dynamic typing, I disagree. But its a discussion thats been going on for so long that Ive concluded its mostly a matter of taste. For Clojurians who like static typing, Spec packs a big punch without removing flexibility. Still, Haskell is pretty great but Im more efficient in Clojure, Your mileage will vary.
- vindarel 6y agoA short add-padding (missing the `newline` parameter): ;; (ql:quickload "str") (defun add-padding (txt &key padding) (with-output-to-string (s) (loop for line in (str:lines txt) do (format s "~a~a~&" (str:repeat padding " ") line))))