1. 5

    Well. I propose making pipes multi-channel & segmented, and using that to write metadata/attributes without inline escaping. stdout.channel("color").write("red"); stdout.write("Hello"). Drag Unix kicking and screaming into the Year of the Justifiably Defensive Lobster!

    1. 6

      Having inline escape codes might not seem pretty, but it’s good for the same reason UTF-8 is good:

      • anything will accept it, even if it doesn’t understand colour.
      • programmers can put a lot less effort in, especially initially, if they don’t care about all of the features.

      Or: don’t add more dimensions to a problem that can already be serialised into 1D, if you start solving problems by adding dimensions then you will end up with a hypercube.

      Drag Unix kicking and screaming into the Year of the Justifiably Defensive Lobster!

      Slippery sidenote: I’m not a fan of using the word ‘modern’ to describe software in a good light, or saying something is bad because it’s “not modern”.

      If there’s is one lesson that we should have learned from the past few decades of software development it’s that you should not assume that current fashions, expectations or trends in programming are in any way better than prior ones. Most of them are just as bad (in different ways), and this is only properly realised years later.

      EDIT: If you’re writing something to be useful, then stick to tried and true development & design practices. Don’t equate “modern” to mean “tried and true”.

      1. 3

        I’m not a fan of using the word ‘modern’ to describe software in a good light

        Same. I roll my eyes whenever I read the phrase “modern programming language”.

        As for UTF-8: it can have just as graceful a fallback. Suppose we want to port ls -l. We’ll start by writing the same bytes as before, but they’ll be annotated by channel. For -rw-rw-r--, we could write that to mode. The next field is the number of hard links. But first comes a space, and there might be multiple spaces to pad out the field. They can be written into tab. Eventually we’ll reach a filename that we might want to color, so we’ll write the whole escape code to escape, and when we get to the \n, we’ll write it to “record-separator”.

        This gets us some slight benefit. You can use ≈jq instead of cut/sed, and feel less nervous about filenames with funny characters. There isn’t a whole lot of benefit until further incremental steps are taken:

        1. Annotate existing output.
        2. Write extra data to channels that are hidden by default. The writer must know if the read end is naive, or only interested in particular subset of channels.
        3. Separate data from presentation. A library can handle rendering to the naive format.
        4. The shell & terminal become type-aware. Their capabilities increase over time. Short filenames hide a full path, and your SSH client sticks the hostname in front. The output of ls doubles as a filemanager. wget & wget no longer makes a mess because each command requests a separate output pane. You can run find ~/Pictures/ | grep cat, pass the output to ImageMagick to make a collage, display it inline, and right click -> rerun on input change. Running program --help attaches a typed grammar for tab-completion. The shell is merely twice as terrifying as a spreadsheet.

        Each step can be reached from the previous. No worlds need to be rewritten. All that’s required is implementing a few syscalls and kickstarting some coreutils.

      2. 2

        How would you read this multi-channel pipe? Color channels must stay synchronized with data but it should be possible to read data without reading color channels. I’m afraid that this is a dilemma.

        1. 1

          “Channels” might be a bad name. When reading, the *buf is filled just like the usual read, but there is a second buffer that contains channel span information. Perhaps “labels” would be a better name. A high-level wrapper for this syscall in Rust might return a Vec<(ChannelName, Vec<u8>)>.

        2. 2

          If you’re modernizing, why not just drop curses for drawing and just use a graphics library?

        1. 6

          Unclear what problem you’re solving. Firefox shouldn’t write anywhere else than the profile directory (see @jefftk’s comment). If you don’t want it to access your user configs in ~/. config. you can redirect $HOME though. But maybe you also want to chroot then?

          If you want to separate all sorts of history and site data and settings and extensions and password storage etc, use different profiles. If you want separate cookie jars (e.g. online identifies) to work in parallel, use the Multi Account Containers Extension.

          1. 8

            The problem this solves is that some websites are now detecting private mode browsing, and using it as an opportunity to be a dick.

            1. 6

              Ugh, that’s bad. Can you give an example of those?

              1. 10

                Nytimes does private mode detection as part of their paywall.

              2. 4

                How do they detect it, and how are they being a dick? I’ve honestly never noticed anything weird in private browsing mode, but I don’t use it all that often either.

            1. 3

              Is there a way in Rust to create a type that blows up if it gets released by falling out of scope?

              I ask this because I wonder if you could do some type trickery to ensure that (for example) a file was explicitly closed at one moment (instead of relying on implicit closing from falling out of scope)

              In any case this is really neat stuff.

              1. 4

                Implement a destructor that panics. It’s called a “drop bomb”.

                The static version of it is analyzing of the destructor got linked.

                1. 2

                  Clever. I’d hate to have to decrypt that error message tho.

                  1. 3

                    I appreciate that! For the reasoning why Rust doesn’t (currently?) have full linear types, see https://gankro.github.io/blah/linear-rust/

                    It’s a surprisingly huge design space once you get into the details.

              1. 3

                ELF magic is more trouble than it’s worth. If you port, or get involved with dlopen, something’s gonna break. It’s the wrong abstraction level, better to use ordinary code. Ideally languages would allow appending to a global static variable at compile time.

                1. 3

                  This’d be great with one of those keyboards that has a little LED screen on each key.

                  1. 7

                    I was able to get them back by disabling xpinstall.signatures.required. It might require a nightly version to actually work? Of course, you’d want to turn it back on once it’s fixed…

                    1. 6

                      As you say, it only seems to work on nightly, unfortunately. Most vexing!

                      1. 3

                        i don’t get why on earth these switches aren’t present in the release versions. this feels like the “caution, hot contents!” prints on takeout cups -.-

                        edit: it works on 60.6.1esr (64-bit) though..

                        1. 4

                          because the lambda person is taught to go around this warinings to install bad extension.

                          1. 3

                            then they are entirely responsible for their misery. i never got the trend of making everything.. more proof than fool proof.

                            displaying a warning which can’t be deactivated would be fine.

                            1. 3

                              No, users are not responsible for products having footguns. It’s unfair to expect non-technical users to understand technical issues, especially when these issues may be misrepresented in a hostile context (e.g. “You have a virus! It’ll murder your googles unless you tick this checkbox and click OK”).

                              Most people don’t need to know what a certificate is. They just want to get on with their life, and not have their entire digital life destroyed, because a product had a “harm me” checkbox.

                              1. 5

                                No, users are not responsible for products having footguns. It’s unfair to expect non-technical users to understand technical issues, especially when these issues may be misrepresented in a hostile context (e.g. “You have a virus! It’ll murder your googles unless you tick this checkbox and click OK”).

                                Is it really a footgun when it’s hidden somewhere in about:config where the first thing you see is a warning about not to touch this? Is it a footgun if I staple my toes with a nail gun, or was I too dumb by not wearing the right shoes?

                                Most people don’t need to know what a certificate is. They just want to get on with their life, and not have their entire digital life destroyed, because a product had a “harm me” checkbox.

                                I seem to be rather alone with this, but I expect some basic knowledge and common sense from people using tools. You need a drivers license, you are supposed to read the manual. These things should be taught in school. Alas, they aren’t, but that doesn’t absolve one from knowing about the technology one is using.

                                1. 2

                                  Is it really a footgun when it’s hidden somewhere in about:config where the first thing you see is a warning about not to touch this?

                                  Yes. “You have a virus! It’ll murder your googles unless you go to about://config, click OK to all the scary warnings (they’re there because of the virus) and then install this.”

                                  These things should be taught in school.

                                  People are culturally trained to not care about school, so even if it was somehow taught it there it wouldn’t have too much of an effect.

                                  Also, where is the manual? How does one even teach people to recognize scams, and then keep them continually up to date on the latest scams for their entire lives? You can’t. The scam that worked in 1999 is nothing like the scams that exist today. The reason that you or I can tell these things is because we do work related to computers and stay up to date on the latest happenings (as evidenced by the fact that we’re on Lobsters). One can’t reasonably expect any “normal” person to do the same.

                                  1. 4

                                    Yes. “You have a virus! It’ll murder your googles unless you go to about://config, click OK to all the scary warnings (they’re there because of the virus) and then install this.”

                                    There are already a plethora of ways to do this. The people that can be manipulated to disable random settings in about:config can just as easily be manipulated to run random code in the console, or install random .exe files from haxx0r.ru

                                    1. 1

                                      So why add one more? The browser is a really lucrative thing to pwn. Lots of accounts can be exploited for profit in easier ways than anything else that could be on the system.

                                    2. 3

                                      i just have a problem with dumbed down versions of everything. it teaches people that they are too stupid, and cannot be trusted with anything. things break and you learn from it. the internet isn’t disneyland, every of these measures to “protect” people from themselves can be worked around. just look at the myriad of shady apps for mobile platforms. additionally: maybe people who believe win-xp themed fake popups telling about a virus should just not use the internet, it will never be safe enough.

                                      tinfoil mode: making the internet feel cozy and safe is to protect business interests, as it is easier to sell things in a walled garden where people aren’t expected to think.

                                      1. 4

                                        Civilization advances by extending the number of important operations which we can perform without thinking about them.

                                        It’s not about stupidity, it’s about ignorance. I can use a light switch without knowing how the electricity was generated, the the glass was blown (let alone the LED manufactured), etc. I can make dinner without knowing how the knife was forged, the grain was harvested, the pasta was shipped, etc. The difference between the browser and all the rest of these household objects is that criminals can become millionaires by hijacking them at scale. I earn my paycheck by understanding browsers and how to make things that go in them so, yeah, for myself I want a browser with lots of places I can tinker with them and break things because sometimes I need to break things to make them work. I love that the web is mutable and weird and it’s easy to shift from consumption to production, to peel back the layers and see how everything works. But I also know that very few users come to the web like a developer does, or have any interest in becoming one. They’ve got a lot of other important, private, or sensitive things to do that insecure systems put in jeopardy. If my light flickers, my power is out, my knife breaks, my pasta is spoiled, my dinner is ruined - none of these things happen because I’m immorally ignorant of how they work.

                                        1. 1

                                          I can make dinner without knowing how the knife was forged, the grain was harvested, the pasta was shipped, etc.

                                          still, you’ll have some sensible ideas of how each of these things are done :)

                                          The difference between the browser and all the rest of these household objects is that criminals can become millionaires by hijacking them at scale.

                                          well.. :P

                                          […] But I also know that very few users come to the web like a developer does, or have any interest in becoming one. They’ve got a lot of other important, private, or sensitive things to do that insecure systems put in jeopardy.

                                          yes. i still don’t see a problem with allowing users to flip switches in about:config after displaying them a warning sign. if they ignore the warning and get bitten it’s on their account.

                                        2. 2

                                          i just have a problem with dumbed down versions of everything. it teaches people that they are too stupid, and cannot be trusted with anything.

                                          If the observed fact that warnings get routinely ignored means that users are stupid to you, then I guess users are stupid (or that software, not even necessarily Firefox, pops up far too many warnings that are too complicated for them to understand or even flat-out false alarms).

                                          1. 1

                                            the too many warnings problem is clearly a software problem, but if i “click them away” and something bad happens, i’m still the reason that it happened. nobody else to blame.

                                            imho unsafe settings could be displayed in firefox a bit like private mode (maybe a little bit redder or something), so that one knows this is not safe. i have no clue about the psychological effects, but know from myself that modal popups are pissing me off, and in “pissed off mode” the warning itself is brushed off as bs, because the modal making my life unreasonably worse.

                                    3. 3

                                      I have very mixed feelings about this. On one hand, I agree with you. On the other hand, I feel like a considerable group of more advanced “power users” is consistently left out in the cold because ever user is always treated like my grandmother.

                                      I wonder if we can’t come up with something better than a yes/no dialog for these sort of things. Like allowing users to continue only after typing the text “dangerous”, sort-of similar to GitHub’s repo delete feature. Or perhaps something else entirely which satisfies both demands.

                                      1. 1

                                        We (power users) need to remember that compared to literally billions of web users, we’re a tiny tiny minority.

                                        In case of Firefox, the Nightly build is the solution for power users (plus, it has much cooler icon).

                                        1. 4

                                          A nightly build is also less stable. Power users deserve a stable browser too. And normal users deserve the opportunity to become power users.

                                          Software should treat adults … like adults.

                                          1. 3

                                            I don’t know if it’s such a “tiny tiny minority”. I suspect there are a lot of people who aren’t IT professionals for a living, but are certainly more clued up than your grandmother on these matters. I will admit I don’t have any hard data to back this up, just an observation from the people around me.

                                            And even for non-technical users there can be good reasons to bypass these sort of warnings, as this current Firefox problem demonstrates.

                                      2. 1

                                        Allowing the average user to kneecap themselves is not productive behaviour for widely installed software. That’s how you get people to install 20 toolbars which slow down everything.

                                        If you want to live without the warning, there is the Beta, Developer and Nightly editions of firefox, which come with the switch to disable signature verification.

                                        1. 2

                                          Allowing the average user to kneecap themselves is not productive behaviour for widely installed software. That’s how you get people to install 20 toolbars which slow down everything.

                                          the problem with this approach is that this way people will never learn. about:config says “warranty void”, so i don’t see a problem.

                                          If you want to live without the warning, there is the Beta, Developer and Nightly editions of firefox, which come with the switch to disable signature verification.

                                          which has more telemetry built in, afaik. this is fine for development and debugging, but i don’t want that for my day-to-day use :)

                                          1. 1

                                            You can also disable more of the telemetry via about:config, though you’d void your warranty.

                                    4. 2

                                      Confirmed working also on 60.6.1esr (64-bit), which is the Debian default version in the apt repos

                                    5. 1

                                      While the switch is present in the version Debian has in the repositories, toggling it doesn’t fix the problem. It allows to install AddOns again, but they are dysfunctional, e.g. NoScript and uBlock Origin have buttons in the menu bar that have no icon and do nothing when clicked.

                                      1. 1

                                        I think you’re right it requires nightly. Not working for me on FF 66.0.3 release (installed from the Arch Linux package).

                                        In fact, I was a bit embarrassed to find I already had signature verification disabled (I was doing some WebExtension development ~18 months ago…)

                                        1. 1

                                          After getting a error message and seeing my addons disabled I tried to set it to true on Android phone and there it seemed to have worked. My installed addons are enabled again. Firefox 66.0.2 on Android.

                                        1. 13

                                          “Digitize books” was something I could get behind. “Train our self-driving cars”? Not so much. Bit of a trojan horse, innit? I prefer to solve the audio captchas, but am occasionally rebuked. Perhaps the scammers will eventually figure out how to automatically solve it. What’ll come next? “Select the members of al qaeda”? The format’s ripe for memeing on.

                                            1. 3

                                              Select all squares that match “Sarah Connor”.

                                              https://pbs.twimg.com/media/DJeAlYTVAAAk7Lp.jpg

                                            1. 0

                                              Try this….

                                              ruby -e 'IO.read( "/dev/zero")'
                                              

                                              If your system turns into treacle for several minutes….. turn swap off and try again.

                                              1. 4

                                                What point are you trying to make with this?

                                                1. 3

                                                  I’m a Linux desktop user. With RAM being plentiful these days, a process using up all of it is overwhelmingly likely to be one that’s running out of control. Rather than spending 10 minutes bringing up top, I’d prefer to let it crash into the OOM-killer. ulimit might be a better way of going about that tho.

                                                  1. 2

                                                    This is what I do on Linux too. As you say, it’s just a case of how long you have to wait until you kill off a runaway process. Do I want it killed automatically or do I want to struggle for several minutes trying to find and kill it manually?

                                                    1. 1

                                                      Sadly ulimit is a borked design and is only partially implemented on linux anyway.

                                                      You will note that no distro I know of sets ulimits for all users, because they cannot know the amount of ram and the load characteristics.

                                                      cgroups are possibly the technology to use these days.

                                                    2. 1

                                                      Users should learn about ulimits I suppose.

                                                      1. 3

                                                        I think its been replaced with k8s… :(

                                                        1. 1

                                                          Sadly ulimit’s are a broken design that is partially implemented and requires tweaking for every different system and load.

                                                        2. 1

                                                          ie. If you do the experiment, you will find if you have swap, your system will start swapping.

                                                          Since the cache hierarchy is so steep these days, your system will be utterly unusable, sometimes for as much as ten minutes or more.

                                                          If you don’t have swap, you may notice a small slow down in your system, and then the OOM killer wakes up and kills the guilty process and you can continue without impairment.

                                                        3. 1

                                                          … why?

                                                          1. 2

                                                            The Article said “Use Swap”, my one liner demonstrates that using swap enables any user to bring any system to it’s knees with a one liner.

                                                            Try my one liner without swap and the OOM killer just kills the culprit and nothing bad happens.

                                                            1. 1

                                                              Thanks for the explanation! It was really unclear what point you were making without actually going ahead and turning a system into treacle, which I wasn’t up for.

                                                        1. 2

                                                          Ah! I love it. |(•◡•)| And I’m glad to make the acquaintance with rofi.

                                                          There’s a project with similar goals, dotXCompose, that I’ve been using for ages. ♫*l is quicker to type than Super+Ilambda⮒, but charpicker has way better discoverability. Maybe it could pull stuff out of the xcompose file?

                                                          1. 2

                                                            Definitely! The real issue is having keywords for sequences, which either have to be pulled from the Unicode database (and are thus unintuitive and generally awful) or made by hand. Either way, it would be trivial to make a script to pull from .XCompose files and just ask the human to put in keywords.

                                                          1. 17

                                                            Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                            Unrelated, I worked at a place a few years ago that built microservices because they wanted the various services to work concurrently, and they were using Ruby. Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough. It also forced me to switch from a spinning disk to a solid state one simply because of the number of files being loaded at once.

                                                            That experience was part of what motivated me to learn Elixir. Years later, I recently worked on an Elixir umbrella app. It was like microservices, but running the whole thing was easy. In production, they deployed one app to one server, one to another, and let both of them depend on a third app, which was deployed to both. All the apps that needed a database shared the same one.

                                                            1. 24

                                                              Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                              Don’t do that. You need to deal with network issues anyways, so bring them all up and let your error handling take care of it.

                                                              1. 8

                                                                trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                                I don’t know you usecase, but that seems to be a complex thing to implement that probably shouldn’t be needed.

                                                                1. 2

                                                                  systemd has service dependencies and sd_notify built-in. Few people use it but it’s totally possible to start a web of services. Of course this doesn’t help with off-machine resources.

                                                                  http://0pointer.de/public/systemd-man/systemd.service.html

                                                                2. 6

                                                                  Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                                  You absolutely can; I do all the time. It may require fundamentally rethinking what we mean by “database” though.

                                                                  Most people think a database is somewhere between “a black box that stores data” and “a black box of hard algorithms for data query” or something like that. To them, they conveniently ignore that the “database” is a service outside of their application, and “can’t transact” across that service boundary either. That’s part of why database migrations and schema changes are so hard: Version 2 and Version 3 of your application are potentially separate services – even in the monolith – and because you “can’t transact” between versions of your application (what does that even mean!?) you’re forced to put logic into your application to deal with both the old schema and the new schema, and you may even often have to do on-the-fly upgrades.

                                                                  Or you just have downtime.

                                                                  Or you have a whole separate system, and your “transaction switch” is on some kind of network load balancer. Blue/green or whatever you want to call it.

                                                                  However there’s a very different way: If your application is the database (and this is easier than you probably think), your crud operations simply need to log their intentions, and then have something read the log which materialises the results into views you can use.

                                                                  One way to do this is to go heavy on the stored procedures. I like this approach, but SQL is a really terrible application language, and many programmers are very bad at SQL. Many databases don’t have an audit table for the stored procedures – there isn’t very good version control for them, so that’s another reason people don’t like it. Maybe the tooling could be improved though.

                                                                  Most people usually go the other way.

                                                                  In Erlang/Elixir, I may (for persistence) use a disk_log to write out arbitrary terms, and have a subscriber pick them up – that is also a gen_server that you can query. At startup, I can read the logs. If the logs are big, my gen_server knows enough to checkpoint – just write out State to another file, and include the offset in the disk log.

                                                                  In Go and Smalltalk you can do something similar.

                                                                  In C, or lots of other languages that don’t have processes, you can still get this functionality with a little thought, because the operating system has processes and fifos/socketpairs for you to use! It feels very similar to writing microservices, which sucks for different reasons (notably the lack of good IPC, e.g. php has serialize), but it’s not the same as microservices: just mutually cooperating processes. Qmail is a great example of this architecture, that is probably just a bit more complex than it would need to be today since the whole world is Linux and iOS now.

                                                                  In q I don’t even need to do that. I can just use the -l and -r options which give me logging/subscription built-in to the runtime. It’s also much more enjoyable because the language doesn’t suck as bad as SQL, and we have great IPC.

                                                                  Putting your data responsibilities in your application isn’t popular though. People actually think redis or Postgresql are fast, and many programmers doubt themselves able to make something as fast (let alone faster). This kind of approach however, tends to be done well around 1000x faster than using “a database” (and maybe done poorly or naïvely only 10x faster), gets you 100% uptime even in the face of schema changes, all of the benefits of a distributed/multiservice application with none of the downsides.

                                                                  This is, as I see it, a serious barrier: Programmers lack the confidence to build things outside of their specialisation (whether they call it “back end” or “front end”) and even terms like “full stack” seem to be (in their normal usage of the term) limited to “code” – very few “full stack” developers seriously consider rolling a new database for every application. And I think they should.

                                                                  1. 1

                                                                    What is q ?

                                                                    1. 1
                                                                  2. 3

                                                                    Another disadvantage of services is that you can’t do a database transaction that includes operations from more than one service.

                                                                    You can using distributed transactions, but that’s a whole other nightmare to contend with.

                                                                    1. 2

                                                                      Unfortunately, trying to boot all the services, the right order, ensuring a service didn’t come up unless one it depended on came up, was tough.

                                                                      Topological sort?

                                                                    1. 1

                                                                      I’ve been using shadowing to deal with Arc and thread::spawn. No indentation or incrementing required:

                                                                      let thing0 = Arc::new(thing);
                                                                      
                                                                      let thing = thing0.clone();
                                                                      thread::spawn(move || …);
                                                                      
                                                                      let thing = thing0.clone();
                                                                      thread::spawn(move || …);
                                                                      
                                                                      1. 1

                                                                        Has anyone tried switching vim up to support object-verb?

                                                                        1. 2

                                                                          Just use visual mode.

                                                                          1. 1

                                                                            This would make Vim’s . (dot) command a lot less powerful.

                                                                            1. 1

                                                                              Or evil-mode?

                                                                            1. 2

                                                                              You’re probably better off avoiding i % 2 is 0, because:

                                                                              >>> x = -923409283409813490234
                                                                              >>> x is x + 0
                                                                              False
                                                                              
                                                                              1. 1

                                                                                Ah good catch, it should be == there.

                                                                              1. 8

                                                                                Great writeup! Thanks for posting this. Reading about puzzle solving in Prolog makes me want to get more into that language.

                                                                                I’m quite new to Prolog, but just being vaguely familiar with the language often makes me think that would be so much easier in Prolog on real life problems. For example, a friend of mine spent 3 full weeks putting together a time plan for a festival using spreadsheets trying to account for people’s availability and the different tents, yet I’m fairly confident that problem could be solved in less than 100 lines of Prolog (which I intend to do before the next festival).

                                                                                That said, the definition of uniq_ppl looks rather clumsy, with its fixed number of arguments and all. Why not just use all_distinct?

                                                                                (Also, can we have a Prolog tag here on Lobsters, please?)

                                                                                1. 4

                                                                                  I agree with a Prolog tag. I think the formal methods tag is very misleading.

                                                                                  1. 3

                                                                                    One common failstate I’ve heard for ‘computer assigned seating’ is that it doesn’t know enough about the more social elements, like that Alice and Bob are in a blood feud going back 10 generations, or that So-and-so is part of a group of friends that would be upset if they got split up. Probably you’d want to keep people near to who they were near last year, since it presumably worked out well enough.

                                                                                    I didn’t get much further than “Hello, World” like a month ago; can Prolog rank & sort its output?

                                                                                    (Also, hello lobste.rs!)

                                                                                    1. 3

                                                                                      I don’t remember if Prolog can rank solutions, but I know you can impose constraints like “person A should not be seated beside person B”. The map region colouring example in the article is a demonstration of this.

                                                                                      1. 3

                                                                                        There are definitely ways to rank output. One way would be to generate potential solutions as a list where each element is a pair of a potential solution and a score for that solution, and select for the maximum.

                                                                                        (Caveat: I’m pretty bad at prolog, but I’m relatively confident that works).

                                                                                        1. 1

                                                                                          One common failstate I’ve heard for ‘computer assigned seating’ is that it doesn’t know enough about the more social elements

                                                                                          Totally agree! I think however that that type of failing is more the fault of the programmer than the language, because there’s nothing preventing you from adding a hates(alice, bob). fact.

                                                                                          1. 2

                                                                                            That requires one of Alice or Bob to actually tell the guy behind the desk that they don’t want to sit together. Mining all the needed information is the hardest part of computer-assigned anything.

                                                                                            1. 2

                                                                                              That requires one of Alice or Bob to actually tell the guy behind the desk that they don’t want to sit together.

                                                                                              Well, yes, that is correct, but that is an issue with a seating plan even when done on paper (although an issue like this is easier to tell to a human being than a GUI that doesn’t have an input for that).

                                                                                              1. 2

                                                                                                It’s also something a human may not “remember” up front, but be reminded of just before attempting that solution.

                                                                                          2. 1

                                                                                            Hello and welcome to Lobsters! Hope you enjoy it! :)

                                                                                          3. 2

                                                                                            I thought of all_distinct/1 there as well, but that’s actually a clp(fd) predicate that only works on integers. It would probably be nicer to use dif(A, B) instead of \+ A = B though.

                                                                                            1. 3

                                                                                              Here’s a general implementation of “these variables are unique”:

                                                                                              pairs(Xs, Pairs) :-
                                                                                                  bagof(X-Y,
                                                                                                        Other^(select(X, Xs, Other),
                                                                                                               member(Y, Other),
                                                                                                               X @< Y),
                                                                                                        Pairs).
                                                                                              
                                                                                              uniq(Vs) :-
                                                                                                  pairs(Vs, Pairs),
                                                                                                  maplist([A-B]>>dif(A, B), Pairs).
                                                                                              

                                                                                              Example use:

                                                                                              ?- uniq([A, B, C]), maplist([X]>>member(X, [1, 2, 3]), [A, B, C]), A = 1.
                                                                                              A = 1,
                                                                                              B = 2,
                                                                                              C = 3 ;
                                                                                              A = 1,
                                                                                              B = 3,
                                                                                              C = 2 ;
                                                                                              false.
                                                                                              
                                                                                              1. 1

                                                                                                Oops, yes, I missed that all_distinct is only for integers.

                                                                                                Regardless, I think it a recursive definition is simpler and more general, for example like this unique relation.