4 ms·
> LISP doesn't really have syntax - you write parse trees directly. Lisp has plenty of syntax, it's just extensible and largely defined in operators. Commonly
by kbp 8y ago
> LISP doesn't really have syntax - you write parse trees directly.
Lisp has plenty of syntax, it's just extensible and largely defined in
operators. Commonly used macros like DEFUN, WITH-OPEN-FILE, and LOOP all add
their own syntax to the language; that's what macros are for. When you put
them together, typical Lisp code ends up looking like
(defun count-words (filespec)
(with-open-file (f filespec)
(loop with counts = (make-hash-table :test 'equal)
for line = (read-line f nil)
while line do
(loop for word in (cl-ppcre:split "\\s+" line) do
(incf (gethash word counts 0)))
finally (return counts))))
Which I don't think is that alien. It translates pretty cleanly into Python:
def count_words(filespec):
with open(filespec) as f:
counts = collections.defaultdict(int)
for line in f:
for word in line.split():
counts[word] += 1
return counts
Do you find the former significantly harder to understand? I don't see how
it's any more like "writing a parse tree directly."
> Why should I write (+ p 2) when most people think (p+2)? This difference
gets worse with more complex expressions.
As mentioned in other comments, there are infix packages available for when
you're writing math-heavy code (or if you just need infix operators), but I
also think that a lot of people don't write very much code with complicated
inline arithmetic in it, and overstate how much the awkward math syntax would
affect them (there are of course plenty of projects that are math-heavy and
where it does make a large difference). When you're defining
variables/functions/classes/etc or calling functions or looping or
whatever, there's not much difference between Lisp and most other languages
aside from whether the bracket is { or ( and which side of the keyword it goes
on; in my experience, that sort of code tends to make up the large bulk of
most codebases in most languages.
edit: Another place where Lisp's default syntax is significantly different from a lot of languages is
something like object.f(x).g(y).h(z), which in Lisp looks like (h (g (f object
x) y) z). This can be remedied with common macros like -> that let you write
(-> object (f x) (g y) (h z)).
- deleted 8y ago[deleted]
- tigershark 8y agoBoth your snippets are exceedingly long, verbose and painful to understand. In C#, that normally is a quite verbose language, you can write just this: IDictionary<string, int> CountWords(string f) => File.ReadAllText(f).Split().ToLookup(w => w).ToDictionary(kv => kv.Key, kv => kv.Count()); Or a bit more concise in F#: let wordsCount f = File.ReadAllText(f).Split() |> Array.groupBy id |> Array.map (fun x |> fst x, (snd x).Length) |> dict
- kbp 8y agoSure, there's other ways to write it, the point of the post was Lisp's syntax, not the algorithm I used to demonstrate some features of it. You could write examples like yours in Lisp or Python, too. As well, your examples both slurp the whole file into memory, which mine avoided. edit: And your C# version is only 24 non-whitespace characters shorter than the Python version, and 20 of those are because you called your variables 'f' instead of 'filespec' and 'w' instead of 'word'. A 4 non-whitespace character difference makes it exceedingly long and verbose? Or are you just advocating 1-letter variable names and avoiding newlines?
- tigershark 8y agoThe c# version is calling only 4 methods and in C# you obviously have to declare the types. It’s the difference between declarative style versus imperative that I wanted to highlight, obviously Python is more compact than C#, but written in that way it becomes more verbose and more difficult to read and write. Write something like that in Lisp and let’s see how it compares.
- deleted 8y ago[deleted]
- kazinator 8y agoIsn't "kv => kv.Key" a lambda function that is called?
- kazinator 8y ago