Hacker News new | ask | show | jobs
by jodrellblank 707 days ago
What is it like? 50 years of historic cruft. Questionable whether there are more trip hazards than usefulness for ordinary coding. A fractured community which feels like there are more Prolog systems than Prolog code. Learning Prolog is less "how do I do things in Prolog" and more "how do I contort my things to avoid tripping over Prolog?".

A few dedicated clever people and idealists and dreamers talking about ontologies and building things I don't understand, e.g. the link in https://news.ycombinator.com/item?id=40994780 that could either be genuinely "Prolog is suitable for things no other language is" or "Fusion is 10 years away" or "Perpetual motion is here and so is cold fusion!", I can't tell. But I suspect from the lack of visible activity out in the wider world, closer to the latter than the former. Or perhaps the people able to make use of its strengths are few and far between.

There's a saying about driving to a town which has been hollowed out and is now a road through some empty store fronts and car parks: "there's no there there". The soul of a place is missing, it's no longer a destination, just some buildings on some land. Prolog has the opposite of that, a main road straight past it, few buildings or people, but there is a there there - an attractor, spark of something interesting and fun. Buried in years of cruft. Might be a Siren's call though, a trap - but if it is it appears less dangerous than the LISP one.

3 comments

> A few dedicated clever people and idealists and dreamers talking about ontologies and building things I don't understand

I was briefly deeply interested in ontologies via OWL and I suspect Prolog has the same issues that I think plague ontologies in general.

They are a fantastic tool for a system complex enough to be nearly useless. Modelling an ontology for a reasonably complex domain is unreasonably difficult. Not because the tools are bad, but because trying to define concrete boundaries around abstract ideas is hard.

What is a camera? A naive attempt would say an item that takes pictures, but that would include X-rays. Are deep-space radio telescopes cameras? Trying to fix those issues then causes second order issues; you can say it’s something that takes images from the visible light spectrum, but then night vision cameras aren’t cameras anymore.

The reasoning systems work well, they just don’t solve the hard part of designing the model.

I had similar discussions with people that wanted to encode published research into ontologies. I would ask researchers what they think - the answer was always great idea. I would then follow up with - How would you use it? No response. I finally concluded that it would never happen.

1. No one wanted it enough to pay for it to happen.

2. There is always a turn over of ideas coming and going which can never be sufficiently updated to keep it useful. Again no one would pay anyway.

Tools like LLMs seem to be fill the role now. I would like to see a Prolog integrated with LLMs is someway (lack of imagination fails me how that would happen).

A theorem prover for the medical literature:

https://github.com/webyrd/mediKanren

http://minikanren.org/workshop/2020/minikanren-2020-paper7.p...

Not prolog though. But gives an idea about the goals behind the classification of science papers.

How would you use it? For searches.

If I want to find something in the brain but not in bone structures. If I want to find something in a kind of cell but that have a nucleus.

They are also extremely useful for automated annotation. Your automated system may annotate with a upper term because it doesn't have enough information to be more precise. That's already a big help for a human to come and put a more precise term.

We are at a convergence of technologies, with ontologies, graphs, llms and logic programming. A lot of people were too early on this and discouraged from pursuing further by people that couldn't grasp why it was so important.

This is why Lenat and CYC had settled on micro-theories. They found it impossible to build a useful universal ontology so had to fracture them on domain boundaries.
I was just pondering if the Prolog universal quantifier would be applicable to reasoning about Cyc frames. Does your comment imply it's not?
I'm somewhat familiar with Cyc but I'd never heard of this development of "micro-theories". It makes perfect sense though - to generalize hugely structured ontologies break as soon as the second person tries to use them or they are used on a slightly different domain.

Anyway, Prolog should be suitable for reasoning over them, but it is only grounded in the "micro-theory" part.

your camera example demonstrates that human knowledge is loosely structured and formalized in general, so you can't create strict onthology. One way to work around is to assign some confidence score on statements, so you will have something like that Nikon device is likely camera, and x-ray machine is unlikely camera based on current world model.
I don’t see an issue with saying “X-ray photography machines, and deep-space radio telescopes, are (or at least contains-a, in the case of the telescope) cameras”. They just aren’t ordinary cameras of the sort that a typical person might take a picture with.

I think most of the reasoning you would want to do with a concept of “camera” that excludes X-ray machines and telescopes, but includes night-vision, could be handled with “portable camera”?

Hm, I guess you probably want to include security cameras though..

Ok. “Portable cameras or security cameras”.

An universal ontology cannot have any notion of an "ordinary" camera, not because of expressive limitations but because it's subjective.

Is a CAT machine a camera? Maybe only its sensor and the computers that reconstruct images? Maybe just the sensor? It mostly depends on your location in the supply chain.

Is a box with a projection plane and no means to capture images a camera? Before about 1830, definitely (and then making photographs became a simple upgrade for your "camera obscura").

I don’t think the “before 1830” case is really an issue. That’s just an example of the meaning of words changing.

I didn’t mean that “ordinary camera” should be a term in the formal ontology. I meant something more like “If you want to formalize the notion of ‘a camera’, it should include the CAT machine and telescope. If you want to address only the types of cameras that you think of as ordinary cameras, you should add extra qualifiers to get at what you mean.” .

(Where, “what you mean” might not get the term “ordinary camera”, but something more clear and descriptive.)

Yes, I think that is the experience, for example, in what we called (or call) data science: most of the time is spent in ETLs rather than using ML methods. In a real company linking data difficulty is not technical but time and resource consuming.
Ontology: Study of the nature of being, becoming, existence or reality, as well as the basic categories of being and their relations (philosophy)

What does that have to do with this?

Is there some use of "ontology" in logic I have not heard of?

It would be this version of ontology: https://en.wikipedia.org/wiki/Ontology_(information_science)

Loosely speaking, ontologies are categories of objects defined by their attributes and relationships to other things. Where a hierarchy is a branching structure where items can only appear on the tree once, ontologies do not require everything to stem from a single "root" node and items can appear in the tree in more than one place.

It's a way of working around how hierarchies can't model some things very well. E.g. "bipedal" is an attribute that can apply to both animals and robots; where does it go in a hierarchy that it can apply to both animals and robots without also implying that robots are animals or vice versa.

Domain Driven Design - one of those things like Agile that triggers all sorts of holy wars - has a lot of overlap with the general concept of ontologies, to the point that I've seen some teams formalize all communication between microservices through a shared "ontology", which in reality was essentially a giant XML based descript of valid nouns and verbs that events could use to communicate between services.

Additionally, there's a good deal of overlap with the "semantic web" concept, which itself had a good deal of hype with very limited (but important) application- even the W3C has some published content on how all three fit together: https://www.w3.org/2001/sw/BestPractices/SE/ODA/

Maybe more in philosophy and classic general AI. Basically ontologies are systems of categorizing and classifying knowledge. E.g. if you want to reason about self driving, you would have an ontology that lets you separate traffic signs from billboards.
In this context ontology means common vocabulary/categories.
What do you mean by LISP as a siren call?

I’ve just started learning clojure and besides the lack of static types (which is pretty harsh for me), it seems like a fun and practical language.

Imagine it's, like, 1980 - or even earlier - and you can work in a language roughly as nice as Clojure, except the rest of the world is stuck working with pre-ANSI C or Pascal or FORTRAN or COBOL or raw assembly language. There's no Python or Java or C# or Ruby or Perl or Haskell or Scala or Kotlin or Rust or JS/TS. Nothing really resembling our modern idea of a high-level language.

(OK, there was Smalltalk. Let's ignore Smalltalk. Lord knows everyone else did.)

That'll alter your perception of reality a bit. Here they were, in possession of a tool massively more powerful - and more elegant - than what everyone else is using. And moreover, everyone else took a look at it and turned their noses up.

Clearly, you and your fellow Lisp programmers are a different breed, capable of seeing further than the rest of the unwashed masses. In a word, you were better than them.

It sounds like I'm being disparaging, but to a certain extent, I don't even think this was totally a wrong attitude to have. Elitist, definitely, but not wholly unwarranted. Lisp really was - in terms of expressiveness, anyway - really that far ahead of the competition. And yet somehow that competition won. The world is cruel and unjust.

So Lisp becomes a kind of Us v. Them cult: if you've heard the good word of McCarthy, you're one of Us. If not, you're best ignored - too stupid to possibly have anything worthwhile to say.

(If you think I'm exaggerating, spend some time reading the words of Usenet Lisp institution Erik Naggum - R.I.P. - who serves as the most extreme but hardly the only example.)

This blinded Lisp diehards to the outside world, which slowly but surely, in many respects, began to catch up or even exceed Lisp.

The other thing is - not only is Lisp a powerful language, at its core is a beautiful and simple and expressive mathematical idea. Combine that with the way macros allow you to extend the language virtually infinitely, there can be a near religiosity at the heart of Lisp - from one lambda all things depend. Lisp isn't just good engineering - it's a glimpse at the fundamental nature of computation, of the universe itself.

I'm not going to sit here and tell you that this is somehow a terrible thing, per se. But it can be incredibly alluring to the right kind of mind, and once you're in its thralls it's hard to get out. You might be working with the tool, but in another sense the tool is working with you. A Siren Song.

There's also the not all small factor that there was glam to Lisp.

Early Internet discourse around programming was dominated by people who had ties to elite universities in the 1980s, who yearned for the times when the US Government was throwing an abundance of money to the AI industry of the time.

They were the ones rubbing elbows with researchers from MIT, Stanford, Harvard, and Berkeley, who were using specialized hardware and software beyond the capabilities available to that of developers working on more mundane applications, all graciously funded by DARPA initiatives.

That experience was, in truth, unrelatable to young people reading the recollections of ESR and RMS of the period, the in-jokes of these people, their ideas and interactions, but the tales of Lisp, the Lisp hackers and their fabled Lisp machines would be extremely appealing to someone who was very passionate about programming, striving for excellence as a programmer, and to advance in life through merit. Paul Graham would seal the deal with his essays.

> (OK, there was Smalltalk. Let's ignore Smalltalk. Lord knows everyone else did.)

As someone that used Smalltalk/V on Windows 3.x, was aware of Smalltalk role on OS/2 and SOM, alongside the whole Visual Age line of products before Sun coming up with Java, there were enough people looking around Smalltalk until 1996.

Learning about the curse of lisp is always an eye opening point in one’s career
Wow, thank you for the context!! That was a fun read. And definitely explains some of the stuff I’ve read about Lisp. (I only ever thought to look into lisp because of this xkcd https://xkcd.com/224/)
Clojure is probably the most beautiful language I've ever worked with. Nothing is perfect, but Clojure is very simple and elegant.
Only downside is I don't know Java, so some things that should be obvious are opaque to me.
You really don’t need to know any java. I don’t know java either.

Even if you’re doing java interop, it’s quite easy to figure it out.

Last time I looked about file IO it involves calling out to some Java class that I had no clue about as I don't use Java. All the doc of the time just assumed you should be able to figure this all out.

Edit: it's been like 5 years

The docs are better now (eg https://clojure-doc.org/articles/cookbooks/files_and_directo... ) but you still need to follow a Javadoc link every now and then for the full story.

Alternatively you can use a library such as https://github.com/babashka/fs .

I agree with the GP that you don't need to know any Java.

This was my experience too, at about the same time. I should really dig back into it at some point.
Java frolicks in opaqueness.
What makes Clojure a non-starter for me is that it runs on the JVM.
Could you expand why? It's not immediately obvious why would that be, my understanding is that the general consensus around here is that the JVM is a superb piece of tech with a bad rap due to java the language.
Slow startup, huge memory consumption, design that inherently favors class-based languages like Java, the frequent need to use Java libraries.
> Slow startup

This makes the jvm a bit less suitable for programmes with short lifetimes (like lambdas), depending on how sensitive startup times are in context... But is mostly irrelevant in long-lived applications like services.

> design that inherently favors class-based languages like Java

Clojure abstracts over this so well that it's really a non-issue for a wide array of use cases / applications. When programming in Clojure, you really don't have to think about objects and classes at all, unless you really insist on doing so.

> frequent need to use Java libraries

This would be going against the grain: you will have a much better time by staying within native Clojure. I've worked on commercial/production applications that barely had any java interop, and whatever java interop there was was rarely ever involved in day to day work.

---

Disclaimer: I also am not a huge fan of the JVM and I really dislike the Java world generally, but it never stood in the way of me getting stuff done with Clojure.

core.logic is pretty neat, too. Especially as it applies to this thread and the ancestor comments.
Lisps don't get in your way, but they also have no opinions, which is problematic for community development. As a static type fan, it's the only language I think the pros outweigh than one con.
Who still has nightmares of infinitely nested parenthesis?
The more nightmarish thing about Clojure is realizing that, in truth, you have no idea what all these dicts you are passing around the terse, nil-punning functions of your codebase hold at any given time.
That was the case for me. I went all in drinking the Clojure koolaid and wrote some small internal CLI tools with it. If I came back to that code a month or two later I could only properly understand it if I opened up a REPL to debug it. I ported those tools to Java and they were dead simple to comprehend.
After a while, lesser the magic, the better.

One of the reasons Golang has had a use case in today's age is there is a need for a programming language with just functions, loops and if/else statements.

Yup. I learned Clojure just so I can use a Lisp and get paid for it, but there is some weird cult against all forms of typing. Even coming from a Common Lisp background, this was strange to me. In Common Lisp, there are implementations (like SBCL and ECL) that can make use of type declarations to produce efficient machine code and allow the compiler to catch errors that would otherwise be run-time errors. There's also other benefits like contextual autocomplete. The autocomplete in Clojure tooling is very basic, and many Clojure libraries try to make up for this by using qualified keywords everywhere. That way, rather than seeing all keywords ever interned, you can type ":some.namespace/" and your editor shows a dozen keys instead of hundreds of unrelated keys.

Many in the Clojure community believe that occasionally validating maps against a schema "at the boundaries" is good enough. In practice, I have found this to be insufficient. Nearly every Clojure programmer I know has had to "chase nils" as a result of a map no longer including a key and several functions passing down a nil value until some function throws an exception. (Note: I don't specify which exception, because it depends on how that nil value gets used!)

Refactoring Clojure code in general is a nightmare, and I suspect it is why many in the community are reluctant to change code in existing libraries and build entirely new things in parallel instead. Backwards compatibility is one often-cited reason, but I do think another reason is that refactoring Clojure code creates an endless game of bug fixing unless you have full test coverage of your codebase and use generative testing everywhere. (I've never seen a Clojure codebase with both of these things. I can count on one hand the number of Clojure codebases where generative testing is used at all).

Function spec instrumentation provides something that feels like runtime type checks in Common Lisp, but now you have to manually run certain functions at the REPL just to ensure some change in your codebase did not introduce a type error.

On the flip side, Java has things like DTOs which always felt too boilerplate-ish for me (though at least it provides useful names for endpoint data when generating Swagger/OpenAPI documentation). Even then, records in Java provide what are essentially maps with type safety and similar characteristics as DTOs.

I think the structural typing offered by languages like OCaml and TypeScript provide exactly what I'd want in Clojure. But when faced with feature requests in Clojure, people will state something like "I have never had a use-case for X, therefore you don't need X". In the case of criticisms, the response is often "I may have ran into X before, but it's so rare that I don't consider it a problem".

I still don't get how Java records can be used for anything like a DTO. Since you're a Clojure dev you may remember the pattern Rich Hickey described as "place oriented programming" :) Nearly every endpoint will have more than 2-3 fields and you really don't want a Java record with more than that many fields for the same reason you don't want a Java method with that many fields e.g. doIt(Long, String,String,Long,String,int,int,String) <-- code smell.

And the problem I always see is something may start off as a Java record and then need to be refactored into a class as soon as 1-2 more fields are added.

> I still don't get how Java records can be used for anything like a DTO

In Clojure, we often deserialize a result set from a database to a vector of maps. These maps have different keys depending on what exactly your query was selecting. In Java, one often "projects" results to some DTO. This is one scenario where records offer identical functionality while avoiding boilerplate.

Regarding "place-oriented programming", records are immutable, so that is one technical advantage they have over handwriting a DTO. And from my short experience using web frameworks like Quarkus, it seems that a lot of the "design patterns" I see in documentation exist to help design easy-to-test programs rather than unfettered mutation.

Additionally, I have found records useful for describing the payload of endpoints that accept map-like data. Without records, I would be writing POJOs with public fields anyway.

Overall, Java records behave like TypeScript interfaces with awkward syntax. I have found them ideal for expressing type-safe, map-like data with minimal boilerplate.

I'm also using it for projections. But to be honest we have a fairly large Quarkus app and only use projections in a few places. For immutable classes with a large number of fields where instances have to be created manually I usually use the builder pattern. But the analogy to typescript interfaces is interesting.
Typed Clojure is interesting. However, until two months ago, it was practically unusable for most Clojure projects because of the lack of type inference in higher-order functions. This has changed, but there's another huge problem: nobody maintains type declarations for widely used libraries. If you look at alternatives to TypeScript, such as ReScript, you will find similar issues.

I still use Clojure, but I am fully aware of the kind of bugs to expect down the road. Typed Clojure would work if I could maintain types for each library I use, but that is simply too much effort on my part.

As for clojure.spec, I already addressed this in my post, but I will state the following.

Schema, Malli, and Spec are not substitutes for a type system. Each of these libraries explicitly state so. You still need to enable instrumentation and run erroneous code violating some contract. Most Clojure programmers have the habit of enabling instrumentation in dev and disabling it in production because validation is an expensive operation. I personally use Malli for data validation and coercion, but it does not make refactoring any easier, nor does it help autocomplete and other development-related tooling.

(Someone will probably link a malli document demonstrating clj-kondo linter generation, but even that is not a substitute. At best it detects arity errors and primitive type mismatches, not the shape of data in a map).

They seem to disappear with parinfer.