Live data from Hacker News

Why I still Lisp

mendhekar.medium.com

101–110 of 240 posts

Re: Why I still Lisp

#101
post #76
post #61

Earlier quoted context omitted.

> If value is not a numeric type, square is not going to be happy. That is not necessarily true. In Common Lisp, with its generic-function based object system, you can extend the operation of any function at any time to cover new types. So, for example, one could define a method for SQUARE that operates on matrices. > What thing that violates a type check would be "perfectly fine to do"? (define (self-apply fn) (fn f…

> (define (self-apply fn) (fn fn)) Out of curiousity, what would be a practical application of this?

See:

http://www.flownet.com/ron/lambda-calculus.html

Re: Why I still Lisp

#102
post #92
post #71

Earlier quoted context omitted.

I spent a lot of time thinking about this. What makes Perl or Clojure such fun languages to work with is they don't impose structure on you. You can do whatever the hell you want. On the other hand result of this is the code represents basically how you think about the problem. Which would be very different for every person. Languages with frameworks like Java+Spring, Ruby+Rails etc. are less "fun" to work with becau…

It is the frameworks that give more rigidity and boilerplate, not so much those languages themselves (although Java does have more boilerplate than Ruby). You have a lot of freedom when you program in plain Java and Ruby vs. using frameworks in those languages. And that is at least partly by design. See the Template Method design pattern, which is the basis of frameworks that use Inversion of Control (IoC).

Clojure frameworks are written by Clojure developers which means they don't give you structure, only tools to realize your freedom.

Frameworks that give a lot of structure are beneficial to novice developer because they need that structure. In absence of supervision, the various articles on the Internet, stack exchange answers on how to write a controller or other piece of Java app, give a novice developer necessary guidance on how to structure their code.

On the other hand as a more mature, knowledgeable and experience developer you may see that this structure is not perfect. It is repetitive and it has a lot of boilerplate and it does not suit well every application.

You may even figure out that every application has their own perfect framework, depending on its size and other characteristics and the problem it is trying to solve.

Clojure lets you design that framework and then write the application in perfect framework for your application.

That framework might be some zero-code decisions (like decisions on where to put which part of the code) but can also be some set of macros up to full blown DSL.

Assuming you are mature developer, you will know how to use these to solve your problem but if you don't then that's where the problem starts.

Re: Why I still Lisp

#103
post #99
post #86

Earlier quoted context omitted.

It may take a while to see the visual clues: indentation, formatting, structure patterns. Beyond simple lists, Lisp uses a variety of list structure patterns for language constructs. It's a bit like learning to ride a bike: initially it looks not possible to balance, steer and move forward at the same time. One thing that's not that usual is that authors can implement new language constructs themselves. Thus one may…

I think it is important distinguish the necessary from accidental complexity. Macros are typically more difficult to understand but if done well that would be because they are sinking complexity from a bunch of code. For example, if a macro implements variations of repeating construct, you are removing those variations from your entire codebase and putting complexity of dealing with that into a single macro. Now, the…

> sinking complexity from a bunch of code

Sometimes macros provide domain-level constructs. This creates very dense code - which can improve code understanding.

One thing I would recommend to put extra effort into macros, especially with these aspects:

One should write documentation what the macro expects and what it does. This way this has not to be inferred from reading the often quite complex code. Document the implemented syntax.

The macro should check the syntax of the forms. Provide error messages for rejected forms.

Re: Why I still Lisp

#104
post #87

Earlier quoted context omitted.

I wonder how much experience you have in the real world. All of us developers had this thought at some point. I've seen terrible code with plenty of quick hacks on top of that, which was running very stable, because it was battle tested for years in production. What do you think will happen when you refactor such code to a better design? All juniors would think this is the best way to get a stable codebase. Reality i…

You might be one of those experienced developers who has gone through their entire career without ever meeting a well designed, beautifully architectured application, and therefore concluded, sensibly, that all real-world applications look like shit if you look inside, and you seem to have come to believe that this is the only possible way. I have a different experience. Code that is well designed makes mistakes look…

> a well designed, beautifully architectured application

I've seen everything during my career, bad code with lots of bugs, bad code running stable. Nice code full of bugs, and nice stable code.

The reason something was stable was never how the code looked, but how battle tested the product was. You will learn, don't worry.

Plus, at a certain point, it's about tradoffs and compromises. I would love to see highly optimized code that is easy to read.

> only tests can tell whether or not it works

Tests are nice, but the real test will be when users start breaking your app.

I'm curious, what kind of product are you writing?

Re: Why I still Lisp

#105
post #46

Earlier quoted context omitted.

It's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything) type T = { [k: string]: number }; const t: T = { one: 1, two: 2, three: 3, }; const makeUpperCaseKeys = (v: T): T => { const keys = Object.keys(v); return keys.reduce((p, c) => { const key = c.charAt(0).toUpperCase() + c.slice(1); return { ...p, [key]: v[c] }; }, {}); }; console.log(makeUpperCaseKeys(t)); // { /…

That's great! Are you making the argument that I won't be able to find an example where doing some transform in a type-safe way is awkward in TypeScript, or just that this one example can be done in TypeScript? By the way, my example was meant to be more like User -> User where there are some string values and some other types of value. You want to do the transformation in a generic way, but still have the type-safe…

[deleted]

Re: Why I still Lisp

#106
post #101
post #76

Earlier quoted context omitted.

> (define (self-apply fn) (fn fn)) Out of curiousity, what would be a practical application of this?

See: http://www.flownet.com/ron/lambda-calculus.html

That didn't answer my question. Let me rephrase it: When would you use

    (define (self-apply fn) (fn fn))
in an actual, real-life situation (outside of teaching lambda calculus)?

Re: Why I still Lisp

#107
post #46

Earlier quoted context omitted.

It's pretty easy to do in Typescript and loses no type safety (without needing to assert or cast anything) type T = { [k: string]: number }; const t: T = { one: 1, two: 2, three: 3, }; const makeUpperCaseKeys = (v: T): T => { const keys = Object.keys(v); return keys.reduce((p, c) => { const key = c.charAt(0).toUpperCase() + c.slice(1); return { ...p, [key]: v[c] }; }, {}); }; console.log(makeUpperCaseKeys(t)); // { /…

That's great! Are you making the argument that I won't be able to find an example where doing some transform in a type-safe way is awkward in TypeScript, or just that this one example can be done in TypeScript? By the way, my example was meant to be more like User -> User where there are some string values and some other types of value. You want to do the transformation in a generic way, but still have the type-safe…

You can try this with typescript 4.1 :

interface User { name: string; age: number; }

type CapitalizeProperties = { [Property in keyof T as Capitalize]: T[Property]; };

type CUser = CapitalizeProperties;

var c : CUser = { Age: 17, Name: "john" }

You can check that the autocompletion works on the c variable.

https://www.typescriptlang.org/play?ssl=1&ssc=1&pln=15&pc=2#...

Re: Why I still Lisp

#108
> Call-by-value

> Mostly Functional

> Dynamically Typed

Sounds a bit like POSIX shell.

Yeah, I know that especially people doing functional programming do not want to be compared to shell scripters, but since I know how horrible shell scripting is, I wonder if there could be a future, where a proper, mostly functional language could be the successor of the very practical bash. I mean, if we aren't doing anything soon, JavaScript might take that place...

Re: Why I still Lisp

#109
post #106
post #101

Earlier quoted context omitted.

See: http://www.flownet.com/ron/lambda-calculus.html

That didn't answer my question. Let me rephrase it: When would you use (define (self-apply fn) (fn fn)) in an actual, real-life situation (outside of teaching lambda calculus)?

Without additional arguments? Never. With additional arguments, it provides the function with access to itself.

This could be used "under the hood" in an implementation to bootstrap the ability of named local functions to have themselves in scope, which is useful for writing ordinary recursion.

Compilers and interpreters can achieve such a thing without any such jig like a Y combinator, because interpreters and compilers work with environments that are re-ified as objects. They are free to manipulate environments and evaluate/compile any piece of code in any environment they see fit.

Re: Why I still Lisp

#110
post #49

Earlier quoted context omitted.

Agree with him. Coming from an OO background I always cringed at the 15,000 line classes with 2000 line methods. Side effects everywhere. In my naivety I thought functional programs with their emphasis on lack of side effects could help. I then encountered a project that was totally functional but written entirely by people with no functional experience. The entire application was unmaintainable even in the most basi…

> Macros modify code structure at runtime so obviously that is fraught with danger. You may have inadvertently misspoke, but macros operate at compile time, at least in the Lisps I have used.

In full Lisp "compile time" is part of application execution.

Now, Clojure is kind of impaired Lisp because it is written for a VM that was not intended to be used this way and so this is not that much pronounced (but you still get REPL, etc.)

Post reply on HN