Hacker Newsnew | past | comments | ask | show | jobs | submit | axle_512's commentslogin

You don’t see them in the same sense you don’t see multiple closing braces in java or c.

The style in lisp is to keep all the closing paren on the same line: ))))

But in java or C you’ll sometimes see a function that ends like: } } } }

(Hmm my newlines didn’t cone thru on those braces)

Not exactly apples to apples comparison, but it illustrates how you can start to unsee those parens.


In a decades old java code base where so many has touched the code. It can look like this:

                            }

                        }

                    }

                }

            }

        }
    }
}


In lisp, nearly everything is written in the same form. I.e. everything either is a function call or looks like one. Once you know that, you pretty much know lisp syntax.

People freak out about the parens. But I think what's the big deal? Functions are called with the paren in front of the function and the args space separated. so f(x, y) in C like syntax becomes: (f x y) - Whoop dee do, not so hard.

And since the syntax is extremely consistent, things that are math "operators" in other langs are just functions in lisp.

For "(+ 1 2 3)" + is actually the name of the function, so we are invoking + function and 1 2 3 are the arguments. Returns 6.

Once you know that, and that function args are evaluated before passed into the function, then you no longer have to worry about operator precedence and parenthesis to control order of operations. Once you get used to it, it's actually a lot simpler.

(* 2 (+ 5 5)) => 20


> In lisp, nearly everything is written in the same form. I.e. everything either is a function call or looks like one. Once you know that, you pretty much know lisp syntax.

Actually not. Lisp has several types of forms. A function call is one. There are atleast two others: macro forms and special forms.

function form with +

  (+ 1 2)
macro form with DEFUN. The syntax for DEFUN is:

  defun function-name lambda-list [[declaration* | documentation]] form*
The function name the is either a symbol or a list of (setf name). The lambda-list has complex syntax with optional, aux, rest and keyword arguments, declaration has a complex declaration syntax, etc...

The third type of form would be built-in syntax. LET is an example. The syntax for LET is:

  let ({var | (var [init-form])}*) declaration* form* => result*
This means that

  (let ((a 1)
        b)
    (setf b a))
is a valid program.

This is not a valid Lisp program, which Lisp will complain about:

    * (let ((a 1 2)
           b)
      (setf b a))
  ; in: LET ((A 1 2) B)
  ;     (A 1 2)
  ;
  ; caught ERROR:
  ;   The LET binding spec (A 1 2) is malformed.

Reason: Lisp expects that bindings are either symbols, lists with a single symbol or pairs with a symbol and a value form. (a 1 2) thus is not valid.

Is Lisp syntax easy? Once you look deeper, it actually isn't. Only a core language with only function calls is relatively easy.

* Lisp writes programs on top of a data structure called s-expressions. S-expressions are easy, Lisp not.

* Lisp usually has the operator as the first element of a lisp -> uniform appearance.

* Lisp has some built-in syntax. Usually as little as possible.

* Lisp lets the developer add new syntax via macros -> zillions of macros and the user needs to learn a few patterns to understand Lisp code.


Note I said "or looks like one".

If you squint a bit, macros and built-ins are similar in structure to functions (they're all s expressions).

I agree with much of what you said, but I still maintain that lisp syntax is still relatively trivial compared to most languages.

I also don't think exposing newcomers to macros on a language that is homoiconic is terribly useful until they're already comfortable with the basic s-expression syntax.


> If you squint a bit, macros and built-ins are similar in structure to functions

Because they have a parenthesis in front and back and the operator as first element. Macros then implement complex code structures between those:

  (foo a b)
and then

  (let ((a 10)
        b)
    (declare (type (integer 0 100) b)
             (type number a))
    (declare (optimize (speed 3))
    (declare (special a b)
             (dynamic-extent a))
    (prog ()
      start
       (setf b (+ a 10))
       (go end)
      end)
    (the integer (+ a a b)))
Now remove the parentheses. Looks like a program in a typical language.

Macro forms have lots of internal structure. For an extreme example check the syntax definition of the LOOP macro. Two pages of EBNF syntax declaration. That there are an opening parentheses and a closing one does not suddenly remove the syntax:

   loop for i from 1 below 10 by 2
          and
        for j from 2 upto 50 by 3
        when foo(i, j)
          collect i into is and j into js and i * j into ps
        when bar(i) > baz (j)
          return list(is, js, ps)
or the Lisp version:

  (loop for i from 1 below 10 by 2
          and
        for j from 2 upto 50 by 3
        when (foo i j)
          collect i into is and j into js and (* i j) into ps
        when (> (bar i) (> baz j))
          return (list is js ps))
Does it LOOK like it has less syntax? Not really.

> lisp syntax is still relatively trivial compared to most languages

Not really. Check out the concept of a code walker in Lisp. That's a tool which understands Lisp syntax and can walk over Lisp code and do transformations.

Here is one:

https://gitlab.common-lisp.net/cl-walker/cl-walker/tree/mast...

Mildly complex... complexity comes in, because Lisp has built-in syntax transformations via macros.


Fair enough, I see your point.

Though stylistically my personal preference is for the macro to remain as simple as possible with limited syntax introduced.


JetBrains based editors are quite nice if you can afford it. Free for students and open-source developers.

PyCharm for python, IntelliJ for java, Cursive for clojure


Emacs for Swift, Objective C, C, C++, Clojure, Python, Java, Javascript, Assembler, Bash, and random other minor stuff.

Wait... there are other IDEs?


At the end of the day, easy debugging is my #1 concern when choosing an editor. Intellisense a pretty close #2.

I just wish I didn't need a completely separate editor for each language. Right now I regularly use PyCharm, PHP Storm, Ruby Mine. I guess I also use ReSharper a lot, but that's slightly different :D


You actually don't need a separate editor for most of the languages (minus C++ with CLion). It's not entirely obvious, but if you use IntelliJ IDEA, there are plugins for the other languages that provide the equivalent functionality of PyCharm, Ruby Mine, etc: https://plugins.jetbrains.com/idea/plugin/631-python https://plugins.jetbrains.com/idea/plugin/1293-ruby https://plugins.jetbrains.com/idea/plugin/6610-php


Another java library with persistent/immutable datastructures is javaslang.


From my experience several years ago:

Distributing binaries for Linux was complex. libstdc++ compatibility across distros or different versions within a single distro wasn't great.

(Compared to Solaris, it seemed like libraries were always backwards compatible. Running old binaries always just worked.)


Many have already said it, but Clojure seems to be gaining in popularity.


I used to have an issue with lisp syntax until someone pointed it out to me like this.

In c and java like languages, you invoke a function like this: f(x)

In lisp, just move the paren before the function name. What's the big deal? (f x)

Similarly, f(g(x)) becomes (f (g x)). All we did was move the paren before the function name.

The syntax is extremely consistent and it makes the lisp syntax trivial to learn. In nearly everything you do, the function name comes first the arguments come next. (+ 1 2) Here + is a function, and you are giving it 2 arguments. There are no special operators or syntax to learn. Just functions!

The mind blowing part comes when you realize that this consistent syntax combined with the fact that the code is really just written in lisp datastructures, is what makes lisp macros so powerful.


Interesting, that does provide a highly consistent base as you say. I might just have to try out Closure with Om/React for my next project.


On the surface, you wouldn't think immutable data structures would offer any significant performance gains. But there are a lot of cool techniques and unforeseen consequences that emerge.

The clojure library "om" is able to use reference equality (instead of a deep comparison) to check for diffs. This results in a 2x or 3x performance gain over mutable data structures.

So I agree with you, this will likely just be a toy OS. But if his design demonstrate huge advantages, the ideas could be adopted by mainstream operating systems.


Forgot to source my info on the "om" library. http://www.infoq.com/news/2014/01/om-react


It is a little clearer to me how this works with things like primitives, but how do you annotate a function that takes a map as input and returns a list? (defn my-keys [m] (keys m))

Edit: Just found Seqable. Looking into it now. This link helped me a lot. https://github.com/clojure/core.typed/wiki/Types


Ambrose pointed me at this link for documentation of core.typed's convenience type wrappers (Vec, Seq, List etc.): http://clojure.github.io/core.typed/#clojure.core.typed/Seq


(ns my-ns (:require [clojure.core.typed :as t :refer [ann]]))

(ann my-keys (All [a] [(t/Map a Any) -> (t/Coll a)])


nice, thanks!


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: