1. 5

    Great write-up, I had no idea the REPL of lisp/smalltalk was so powerful. I need to get around to learning clojure.

    I think the elixir* REPL fits the bill for the most part - if I start up one iex instance and connect to it from another node I can define modules/functions and they show up everywhere. And for hot-fixing in production one can connect to a running erlang/elixir node and fix modules/functions on the REPL live, and as long as the node doesn’t get restarted the fix will be there.

    * erlang doesn’t quite fit the bill since one can’t define modules/functions on the REPL, you have to compile them from the REPL.

    1. 3

      Does Clojure actually have these breakloops though? I think I’ve seen some libraries that allow doing parts of it (restarts), but isn’t the default a stacktrace and “back to the prompt”?

      1. 1

        You’re correct. Interactivity and REPL affordances are areas where Clojure–otherwise an advancement over earlier Lisps–really suffers compared to, for instance, Common Lisp. You don’t have restarts, there is a lot you can’t do from the REPL, and it’s easy to get a REPL into a broken state that can’t be fixed without either a full process restart or using something like Stuart Sierra’s Component to force a full reload of your project (unless you know a ton about both the JVM and the internals of the Clojure compiler). You also can’t take a snapshot of a running image and start it back up later, as you can with other Lisps (and I believe Smalltalk). (This can be useful for creating significant applications that start up very quickly; not coincidentally, Clojure apps start up notoriously slowly.)

        1. 1

          Well, prompt being the Clojure repl, but you’re correct that the breakloop isn’t implemented, as far as I got in the language. You can must implement the new function and re-execute, so you lose all of the context previous to the break. I think with all of the customizability of what happens when a stack trace happens, it’s possibly possible.

          I THINK the expected use with Clojure is to try to keep functions so small and side effect free that they are easy to iterate on in a vacuum. Smalltalk and CL have not doubled down on functional and software transactional memory like Clojure has. That makes this a little more nuanced than “has/doesn’t have a feature”.

      1. 3

        Wouldn’t it make more sense to just put everybody in a list and shuffle the list? Each person then gifts to the next person in the list. Fast, simple, guaranteed 1-cycle, no need to find a hamiltonian.

        Doesn’t handle the additional constraints, but that’s easier to fix here than in his provided code, which looks like it can fail even if a hamiltonian cycle exists.

        1. 1

          determining whether an arbitrary graph has a hamiltonian cycle is an NP-complete problem, so there is no known efficient algorithm for this problem. Now, if you know that multiple hamiltonian cycles exist (because the graph is fully or mostly connected and you can easily find some by hand) and you just want to generate a random one (so you don’t spoil secret santa for yourself), you can just keep iterating the OP’s algorithm or generating random permutations until you find one satisfying the constraints. If your graph has few enough constraints the majority of all possible permutations will be valid, so the chance of needing to generate N permutations to find a valid one drops exponentially, and on average you will only need to generate a constant number of permutations, and then given that you can generate random permutations in O(N) time, the average time complexity is a probabilistic O(N). The time complexity of an iteration of OP’s algorithm depends on the implementation of the collections used but it’s probably amortized O(N).

          1. 2

            I believe Hillel argues you don’t need to solve Hamiltonian cycles to solve the original problem in the blogpost. Ie. it’s overengineered.

            1. 1

              That’s what I was thinking. His graph is almost-complete, so almost every random shuffle will map to a Hamiltonian cycle.

        1. 2

          What’s your plan for making sure the tool can discover actions even for, let’s say, non-semantic SPAs? ie. it might have onClick handlers on arbitrary divs, instead of as or buttons.

          I guess another way to ask is: when in the example you say:

          WebCheck generates click actions for all clickable elements.

          What is the definition of all clickable elements?

          I guess it could be a nice way to force folks to make their SPAs more accessible by requiring either correct elements or some ARIA / role=“button”-like attributes… But to help adoption, it should be possible for users to say their own rules on what’s clickable?

          1. 2

            Yeah, that’s a good point. Currently, WebCheck has its rather strict rules about “clickability”, like it has to be an anchor, button, or submit input, not be disabled or out-of-viewport, and so on. Maybe there is need for a custom “forced” click or whatever to support such JS solutions.

            1. 1

              Most frontend frameworks bind a document click handler and then dispatch events based on the current target.

              Figuring out which elements have event handlers attached statically is essentially impossible in these cases, other than by instrumenting all common frameworks.

              1. 1

                Yeah. Ultimately, it’s up to the user to define a set of possible actions (in the spec) that provide good enough coverage. WebCheck can be somewhat smart, but the specification writer might need to narrow down the search and be more specific than just “all possible clicks”.

                1. 1

                  Yeah - that was roughly where I got to when I looked at implementing a similar tool (targeting screenshot testing).

                  I’d actually be quite interested in a SAAS which would explore the state space of a page and show me screenshots of all the unique states it finds (particularly if it does so for a few browsers / screen sizes). Being able to attach an image to a pull request showing what the page looked like before / after is awesome but often overlooked.

                  1. 1

                    Definitely! I’ve thought about attaching screenshots in WebCheck to introspect failed state transitions. I don’t really have any plans yet for non-failing behaviors, but I guess it could be an option!

                    1. 1

                      Selling any kind of developer tooling is super hard - here’s hoping for your success!

                      1. 1

                        Ugh, yeah it’s likely a steep uphill battle.Maybe if I can win the hearts of developers, but it’s hard with test tools. I think it’s not enough to just “find weird bugs”. It has to do that without adding a bunch of effort, because in many jobs you aren’t encouraged to do advanced testing or formal specification. It’s by your own choice. If WebCheck can help without introducing tons of extra work, I think it might be very appealing.

            1. 1

              I’m going to do these in Haskell again, but I won’t beat myself up if I can’t get everything done on time. For instance, I’m still working on 24 from last year, so.

              1. 4

                I’m still working on 24 from last year, so.

                I took some time to finish last year’s puzzles recently. I found days 15, 20 and 23 the most tricky. IMO, day 15 was just a general pain in the ass and not very much fun.

                1. 2

                  Same here[1]. 2017 was a great year in this competition , and I went into 2018 with high hopes, only to be … discouraged… by day 15. I’ve got 38 stars out of 50, but I did not enjoy last year as much as previous competitions.

                  [1] except the Haskell part. Perl 4 lyfe.

                  1. 2

                    I burned out on day 15.

                    1. 1

                      Yeah, I burnt out on it, running into a few really shitty problems, or at least, problems that I was not well suited to solve. Still, I’ll give it a shot again. My Haskell is very primitive, basically baby-talk, but I enjoy an excuse to play in that sandbox.

                  1. 5

                    After hearing an extremely cheesy quote in a YouTube video about shaolin monks, I’m writing out a list of all side-projects I’d love to work on, selecting one of them and making a plan for what I’ll do about specifically this one the following week.

                    (I’m very much an “do this thing for a week, that thing for the next one, never finishing anything” guy.)

                    1. 2

                      I did this in my bullet journal, and I like to think it was a really useful exercise. There’s a list of “ideas for projects” to record and not forget project ideas, but I’m trying to be focused on one thing at a time.

                    1. 3

                      Every languge that complies/transpiles to JS want to connect to npm to use this huge ecosystem.

                      Not really, Elm has its own walled garden :)

                        1. 1

                          (still re native modules, not re the main point of the link you posted): This datapoint might not mean much to you, but as a person that would have a few usages for native modules I’m still glad they were disallowed from userland code ¯\_(ツ)_/¯

                      1. 6

                        I am so looking forward to this… in fact, I am planning to set my alarm at 06:00 on Saturday (local time when the challenge drops) to get to work ASAP.

                        1. 10

                          I woke up 06:00 everyday Dec1-Dec25 last year to solve the problems and stream myself doing it. Expect yourself to stumble for minutes on stuff that your fully-awake-you would do in seconds :)

                          Also, if you can automate copy-pasting the input from the website, do it. Nothing worse than accidentally deleting a line-break or a character during manual copy-pasting and then spending an hour figuring out what the hell’s wrong.

                          Here’s my automation with curl, sed and tmux: https://github.com/Janiczek/advent-of-code/blob/master/start.sh

                          1. 3

                            Thanks a lot!

                            I’m purposefully not going to stress trying to get on the leaderboard this year (because it was much harder last year than 2016!), I’m just really hyped to get some brain candy!

                        1. 2

                          Very nice. I have to look at how the keyboard stuff is being made - would be nice for Twitch streaming.

                          1. 7

                            Here is mine I’m running vanilla GNU Emacs (was previously on neovim for a year but vimscript is not an adecuate programming language) and I also use vis or vi when I need to edit something quick. Vis is beautiful but had to let it go because it lacks community, and interactive programming for Clojure and Common Lisp with Emacs cannot be beat (at the moment). I’ve been using VoidLinux for three years on a T410s, and I’m planning on moving permanently to OpenBSD because of its stability, cohesiveness and vision. st is the terminal emulator of my preference, because it has a clean code base, it runs fast and with minimal memory footprint. Window manager is cwm.

                            1. 2

                              I really like the color scheme. Could you please share it?

                              1. 2

                                Right now, I’m at work, but promise to upload it when I get home. It’s a modified version of punpun-light for emacs. I changed some colors (for st and emacs) using the palette from inkstained-vim.

                                1. 1

                                  Also, what’s the font? (Works really well with the color scheme)

                                  EDIT: oh, I realized it might be the Iosevka Slab that’s mentioned in the screenshot? :facepalm:

                                  1. 1

                                    :) . It is indeed Iosevka Slab, it is a beautiful font with decent hinting (not Luculent’s level of hinting but still very good) it also has decent UTF-8 support and looks elegant in my opinion, I like semicondensed fonts that look large and tall.

                                    1. 1

                                      I’ve tried to emulate that theme in Vim and I like the result :) https://twitter.com/janiczek/status/1057610214923472898

                                      1. 1

                                        It looks outstanding. I think I’m going to continue modifications on it (basically adding foreground colors for faces of not previously supported modes: cider-mode, company-mode), publish it on MELPA and call it ‘puninked’ because (mine version) mixes palettes with punpun from Emacs and inkstained from Vim, e-inky is also a tempting name. Now, I’m curious why it doesn’t work with sans-serif Iosevka on your machine? is it the terminal emulator?

                                        1. 1

                                          I meant the “not working” mostly as an aesthetic combination. (The terminal can show the combinations just fine.) Can’t even say why those specific combinations work well for me. Maybe e-ink -> Kindle -> serif font is the association in my brain? ¯\_(ツ)_/¯

                                          I named the theme paper in my vimfiles :) Here it is if anybody wants to try. https://gist.github.com/Janiczek/9730ec0e1b60e59220ea0a24e2d4c09b

                                          It mostly evolves as I go and edit different filetypes with it and find something that could be better :)

                                          1. 1

                                            In regards of using serif with that particular color scheme I think you are right. In my case it feels really comfortable reading text for hours at a time with zero-fatigue, a relaxed experience.

                                2. 1

                                  Huh, cwm has shadows? Or is that a separate compositor feature?

                                  1. 1

                                    You are correct, I’m using compton, changing only the shadow-opacity to 0.3, and adding Firefox class windows exceptions, the rest is the default configuration.

                                  2. 1

                                    Can I ask, is this you leaving Void or you going to OpenBSD? Which part do you think is the bigger driver in your switch?

                                    1. 1

                                      Honestly, going OpenBSD is the only driver here. I think it is the last true Unix system these days. GNU (the userland utilities) are fragmented and incorporate too much ‘features’, and Linux is getting more bloat on every release. OpenBSD developers take appropriate decisions on design with security as a first consideration.

                                  1. 1

                                    On Linux I had to change the signal 17 to 19 and 19 to 18, according to trap -l

                                    1. 2

                                      Hi,

                                      thanks for input.

                                      I modified the desktop-pause.sh script to use kill -SIGCONT PID and kill -SIGSTOP PID commands instead.

                                      Change:

                                      https://github.com/vermaden/scripts/commit/f71ac87766b076d17b42a706757ded2170a51e8c

                                      Now it should work on FreeBSD and Linux without modifications.

                                      1. 1

                                        As a note, I do the same thing for macOS for firefox. I just use pkill -STOP basically, no wrapper script. I’m almost always in a terminal so it being in my history is fine enough for me.

                                      2. 1

                                        I made another modification with uname/case so all Linux systems should work properly now.

                                        There was problem with Ubuntu 16.04 which uses Dash as /bin/sh.

                                      1. 4

                                        Thanks for adding algebraic datatypes in!

                                        1. 4

                                          That textfile blog style is absolutely beautiful. @causal_agent, thanks for putting in the notice on how you created it!

                                          1. 1

                                            Apart from the repo (https://code.causal.agency/june/text.causal.agency), where can I find more info on the creation by the author? Love it.

                                            1. 2

                                              Hi! What would you like to know?

                                              1. 2

                                                I am not yet a *nix nor BSD + manpage pro, but I love the idea of tech posts as man pages / .txt files. Are the .7 source files used for a specific reason? The script for building is so simple, as well.

                                                I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                                                1. 4

                                                  I’m really keen on simplicity these days, especially when it comes to the bloat of the web, so I try to set a good example, and this is something I can learn from for sure.

                                                  I’d be the first person to say, “Yeah, make things simpler!” but a plaintext page using spaces for indentation is actually a degraded experience online. The sweet spot for the web is probably a tasteful use of HTML with no Javascript, and a pinch of CSS.

                                                  Look, even the OpenBSD man pages are rendered online with HTML rather than text. https://man.openbsd.org/mdoc.7 Try resizing the page width and watch how it adjusts to stay readable. Now try different widths with text.casual.agency and look how you get jagged line wrap.

                                                  Perhaps you’ll argue, “Resize the width, what you do you mean? I’m on lynx!” But even lynx takes cues from HTML tags to render the page better.

                                                  Finally, you can probably have mdoc output to HTML rather than text and not have to change your page description. Mandoc has a “-Thtml” flag for this, and maybe mdoc has something similar.

                                                  1. 1

                                                    Fair points, and that’s exactly what I was hoping I’d find (when it comes to HTML). Being able to build for .txt and .html files is something I’d like to explore, and you’ve helped. And thanks for the -Thtml lead.

                                                  2. 2

                                                    The extension used for man pages is the digit corresponding to the manual section they’re for. 7 is the “Miscellaneous Information” section which is the only one that fits. You can read about mandoc and mdoc at http://mandoc.bsd.lv, in particular the mdoc(7) page for authors http://mandoc.bsd.lv/man/mdoc.7.html. I might write a little about what I like about mdoc soon.

                                                    There’s some interesting background on the build command, mandoc | sed $'s/.\b//g'. When man pages are formatted for display as text, bold text is output as “A\bA” (where “\b” is ASCII backspace) and underlined text is output as “_\bA”, because that was how you achieved those on a teletypewriter. Print A, move back, print A again over it, print underscore, move back, print A over it. Nowadays it’s actually the pager less(1) which interprets those sequences and renders them in your terminal’s bold and underline modes. If you just print the output of mandoc to the terminal, it will look like plain text with no formatting, because the terminal interprets the backspaces and just deletes the first “A” or “_”. The sed command removes those sequences to create a plain text file.

                                                    1. 1

                                                      Thank you for the detailed response; I had no idea about that background nor why the extension was .7. So interesting! I’ll read up on mandoc & mdoc, and I look forward to your writeup.

                                                      Thanks again

                                            1. 2

                                              I would love to see research on using an AFL-style genetic algorithm based on (branch) coverage feedback for generating test cases in a QuickCheck-style property testing framework. You could do that with clang’s -fsanitize-coverage options, similar to what libFuzzer does but with type-aware input generation, shrinking, etc.

                                              1. 1

                                                This is something I’ve been wanting to do as a side-project for very long time. Instrument the output of Elm compiler with code coverage stats in the runtime and use these stats from within the test runner for some kind of coverage-maximizing AFL-style fuzzers.

                                              1. 4

                                                Yes, generative/property/fuzz tests are awesome. I use them in Elm whenever I can. I’ve also written a library that uses them for the “Msg / Model / update` triplets of The Elm Architecture: http://package.elm-lang.org/packages/Janiczek/elm-architecture-test/latest

                                                Used them eg. on my implementation of a text editor, and they found so many edge cases, you wouldn’t believe. https://github.com/Janiczek/elm-editor/blob/master/tests/CodeEditor.elm

                                                They effectively allow you to pin down the behaviour of a function to a certain degree; giving you counter-examples like “You said the cursor wouldn’t go to a negative column, but if you do [Insert ‘a’, Left, Backspace], the cursor is -1!”, with the Msg list minimized and all that (it probably found the bug with ~100 Msgs in the list, and threw out those that don’t matter)

                                                EDIT: What would I love in generative testing would be some scheme that allows for it to be a monad (to have a andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b function) and still be able to shrink well.

                                                1. 3

                                                  EDIT: What would I love in generative testing would be some scheme that allows for it to be a monad (to have a andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b function) and still be able to shrink well.

                                                  FWIW this is literally the main innovation in Hypothesis. :-)

                                                1. 6

                                                  Yep, this is how I figured out monads too, but when using Rust! There is more to them though - the laws are important, but it’s sometimes easier to learn them by examples first!

                                                  1. 3

                                                    Can you show an example where a monad is useful in a Rust program?

                                                    (I’m not a functional programmer, and have never knowingly used a monad)

                                                    1. 10

                                                      I learned about monads via Maybe in Haskell; the equivalent in Rust is called Option.

                                                      Option<T> is a type that can hold something or nothing:

                                                      enum Option<T> {
                                                          None,
                                                          Some(T),
                                                      }
                                                      

                                                      Rust doesn’t have null; you use option instead.

                                                      Options are a particular instance of the more general Monad concept. Monads have two important operations; Haskell calls them “return” and “bind”. Rust isn’t able to express Monads as a general abstraction, and so doesn’t have a particular name. For Option<T>, return is the Some constructor, that is,

                                                      let x = Option::Some("hello");
                                                      

                                                      return takes some type T, in this case, a string slice, and creates an Option<T>. So here, x has the type Option<&str>.

                                                      bind takes two arguments: something of the monad type, and a function. This function takes something of a type, and returns an instance of the monad type. That’s… not well worded. Let’s look at the code. For Option<T>, bind is called and_then. Here’s how you use it:

                                                      let x = Option::Some("Hello");
                                                      let y = x.and_then(|arg| Some(format!("{}!!!", arg)));
                                                      
                                                      println!("{:?}", y);
                                                      

                                                      this will print Some("Hello!!!"). The trick is this: the function it takes as an argument only gets called if the Option is Some; if it’s None, nothing happens. This lets you compose things together, and reduces boilerplate when doing so. Let’s look at how and_then is defined:

                                                      fn and_then<U, F>(self, f: F) -> Option<U> 
                                                      where F: FnOnce(T) -> Option<U>
                                                      {
                                                          match self {
                                                              Some(x) => f(x),
                                                              None => None,
                                                          }
                                                      }
                                                      

                                                      So, and_then takes an instance of Option and a function, f. It then matches on the instance, and if it’s Some, calls f passing in the information inside the option. If it’s None, then it’s just propagated.

                                                      How is this actually useful? Well, these little patterns form building blocks you can use to easily compose code. With just one and_then call, it’s not that much shorter than the match, but with multiple, it’s much more clear what’s going on. But beyond that, other types are also monads, and therefore have bind and return! Rust’s Result<T, E> type, similar to Haskell’s Either, also has and_then and Ok. So once you learn the and_then pattern, you can apply it across a wide array of types.

                                                      Make sense?

                                                      1. 3

                                                        Make sense?

                                                        It absolutely does! I’ve used and_then extensively in my own Rust code, but never known that I was using a monad. Thanks for the explanation Steve.

                                                        But there’s one gap in my understanding now. Languages like Haskell need monads to express things with side-effects like IO (right?). What’s unique about a monad that allows the expression of side effects in these languages?

                                                        1. 7

                                                          No problem!

                                                          This is also why Rust “can’t express monads”, we can have instances of individual monads, but can’t express the higher concept of monads themselves. For that, we’d need a way to talk about “the type of a type”, which is another phrasing for “higher minded types”.

                                                          So, originally, Haskell didn’t have monads, and IO was done another way. So it’s not required. But, I am about to board a flight, so my answer will have to wait a bit. Maybe someone else will chime in too.

                                                          1. 2

                                                            higher minded types

                                                            (Just so others don’t get confused, I think you meant “kinded” here, right?)

                                                            1. 1

                                                              Heh, yes. Thanks.

                                                          2. 3

                                                            A monad has the ability to express sequence, which is useful for imperative programming. It’s not unique, e.g. you can write many imperative programs using just monoid, functor, applicative or many other tools.

                                                            The useful function you get out of realising that IO forms a Monad is:

                                                            (>>=) :: IO a -> (a -> IO b) -> IO b
                                                            

                                                            An example of using this function:

                                                            getLine >>= putStrLn
                                                            
                                                            1. 4

                                                              I should say Monad is unique in being able to express that line of code, but there’s many imperative programs which don’t need Monad. For example, just Semigroup can be used for things like this:

                                                              putStrLn "Hello" <> putStrLn "World"
                                                              

                                                              Or we could read some stuff in with Applicative:

                                                              data Person = Person { firstName :: String, lastName :: String }
                                                              liftA2 Person getLine getLine
                                                              

                                                              So Monad isn’t about side-effects or imperative programming, it’s just that imperative programming has a useful Monad, among other things.

                                                              1. 2

                                                                You are way ahead of me here and I’m probably starting to look silly, but isn’t expressing sequence in imperative languages trivial?

                                                                For example (Python):

                                                                x = f.readline()
                                                                print(x)
                                                                

                                                                x must be evaluated first because it is an argument of the second line. So sequence falls out of the hat.

                                                                Perhaps in a language like Haskell where you have laziness, you can never be sure if you have guarantees of sequence, and that’s why a monad is more useful in that context? Even then, surely data dependencies somewhat impose an ordering to evaluation?

                                                                For me, the utility of Steve’s and_then example wasn’t only about sequence, it was also about being able to (concisely) stop early if a None arose in the chain. That’s certainly useful.

                                                                1. 2

                                                                  but isn’t expressing sequence in imperative languages trivial?

                                                                  Yes.

                                                                  In Haskell it is too:

                                                                  (>>=) :: IO a -> (a -> IO b) -> IO b
                                                                  

                                                                  But we generalise that function signature to Monad:

                                                                  (>>=) :: Monad m => m a -> (a -> m b) -> m b
                                                                  

                                                                  We don’t have a built in idea of sequence. We just have functions like these. A generalisation which comes out is Monad. It just gives code reuse.

                                                                  1. 1

                                                                    Maybe is an instance of a monad, and there are many different kinds of monads. If you think of Maybe as “a monad that uses and_then for sequencing”, then “vanilla” sequencing can be seen as “a monad that uses id for sequencing” (and Promises in JavaScript can be seen as “a monad that uses Promise#flatMap for sequencing”).

                                                                    Yes, expressing sequence in eager imperative languages is trivial because you can write statements one after the other. Now imagine a language where you have no statements, and instead everything is expressions. In this expression-only language, you can still express sequence by using data dependencies (you hit this nail right on the head). What would that look like? Probably something like this (in pseudo-JavaScript):

                                                                    function (next2) {
                                                                      (function (next) {
                                                                        next(f.readline())
                                                                      })(function (readline_result) {
                                                                        next2(print(readline_result))
                                                                      })
                                                                    }
                                                                    

                                                                    with additional plumbing so that each following step has access to the variables bound in all steps before it (e.g. by passing a dictionary of in-scope variables). A monad captures the spirit of this, so instead of doing all the plumbing yourself, you choose a specific implementation of >>= that does your plumbing for you. The “vanilla” monad’s (this is not a real thing, I’m just making up this name to mean “plain old imperative sequences”) implementation of >>= just does argument plumbing for you, whereas the Maybe monad’s implementation of >>= also checks whether things are None, and the Promise monad’s implementation of >>= also calls Promise#then and flattens any nested promises for you.

                                                                    What’s useful here is the idea that there is this set of data structures (i.e. monads) that capture different meanings of “sequencing”, and that they all have a similar interface (e.g. they have all an implementation of >>= and return with the same signature) so you can write functions that are generic over all of them.

                                                                    Does that make sense?

                                                                2. 2

                                                                  There is a comment below saying it pretty succintly:

                                                                  A monad is basically defined around the idea that we can’t always undo whatever we just did (…)

                                                                  To make that concrete, readStuffFromDisk |> IO.andThen (\stuff -> printStuff stuff) - in the function after andThen, the “stuff” is made available to you - the function runs after the side effect happened. You can say it needed specific API and the concept of monads satisfies that API.

                                                                  Modelling IO with monads allows you to run functions a -> IO b (take a pure value and do an effectful function on it). Compare that to functions like a -> b (Functor). These wouldn’t cut it - let’s say you’d read a String from the disk - you could then only convert it to another string but not do an additional effect.

                                                                  EDIT: I might not have got the wording entirely right. I ommited a part of the type annotation that says the a comes an effect already. With Functor you could not reuse values that came from an effect; with Monad you can.

                                                          1. 9

                                                            I know this is not the point of your article, but did you ever find the Maybe monad instance that is in Elm core library? ie. Maybe.andThen?

                                                            With it the motivating example looks like:

                                                            comments
                                                                |> Maybe.andThen List.first
                                                                |> Maybe.map (\c -> div [ id "first-comment" ] [ text c ])
                                                                |> Maybe.withDefault (div [] [ text "No comments" ])
                                                            
                                                            1. 5

                                                              I did not, but I figured there would be something like this somewhere in the Elm ecosystem. I wrote this a while ago and I haven’t used Elm in at least 8 months so excuse my ignorance, and thank you for pointing this out.

                                                            1. 3

                                                              The author claims they’re a programmer, but they still clicked 338 checkboxes manually? Sounds fishy :)

                                                              Here’s what I’ve done on Tumblr, which also has something similar.

                                                              for (var x of jQuery("input[checked]")) {jQuery(x).removeAttr("checked");}

                                                              1. 11

                                                                The author is a programmer, a software architect, an hacker, and a curious person in general.

                                                                I can conceive several ways to fool your smart jquery script. If you cannot think of them yourself, you shouldn’t code in Javascript, actually.

                                                                But also I’m a UI and UX designer, at work.

                                                                I was surprised to see a nice UI with such a stupid mistake.

                                                                I hoped the developer on the other end was cool enough to surprise me.

                                                                After the first ten clicks I realized she was not that smart.

                                                                I hit F12. But then I thought “my users cannot hit F12: lets walk their path and see how I feel”.

                                                                I’m not stupid. I simply care.

                                                                1. 2

                                                                  I can conceive several ways to fool your smart jquery script. If you cannot think of them yourself, you shouldn’t code in Javascript, actually.

                                                                  • I don’t think he was claiming his solution was a fit for all
                                                                  • So by your logic only people who know DOM JS should code in JS? ;)

                                                                  I know this was a reply to a slightly provocative comment in defense of the author, but this in particular seems a little silly

                                                                  1. 5

                                                                    I’m the author. And actually I’m sorry for the tone of the reply: I’m tired, and I didn’t intended the @janiczek’s post as a joke for me, but as an attempt to justify InfoWorld by calling me fishy.

                                                                    I’m fishy, definitely! :-)

                                                                    But I also care about users. And I’m an European fish…

                                                                    So by your logic only people who know DOM JS should code in JS? ;)

                                                                    Nobody should code in JS. Really. Nobody should.

                                                                    But yes, if you don’t know how DOM JS has been interpreted in the last 10 years, I think you shouldn’t code in JavaScript professionally. You might think I’m exaggerating to get a point, but trust me: everything is still there, under the hood. Ready to break.

                                                                    1. 2

                                                                      Thanks for the kind reply. I wasn’t trying to provoke myself, just point out something that seemed a bit off :) Professionally? Perhaps your right in a perfect world, but the fact remains there will always be code monkeys that build or maintain simple systems for a customer base that can’t pay for a seasoned developer. Regardless, I agree with the pain point of your article :)

                                                                      1. 3

                                                                        Mm, I kind of feel like as a profession we should try to have more respect for our own work. Software can cause significant harm, and we’ve all just collectively agreed that it’s okay to prop up companies that want to build broken things and not properly maintain them. Maybe companies that aren’t willing to spend the money to build safe software shouldn’t have the privilege of getting engineers to work for them.

                                                                        I know that’s a tangent and not really what you were trying to address.

                                                                        1. 3

                                                                          I completely agree with your first statement, having respect for your own work is a great virtue.

                                                                          The devil is in the details in regards to companies/individuals who provide shoddy services. Outside passionate and informed social circles, it’s customers vote with their pockets (counting data as a form of currency here), whether that be for trading for convenience or just a result of plain ignorance.

                                                                          Unfortunately there aren’t any easy remedies to this problem. Shoddy companies/individuals will find ways to work their way around regulations, and customers will quite happily dig themselves into holes in pursuit of the cheapest or quickest solution. That doesn’t mean you don’t try, in fact I personally think one of the best tactics we can use for problems such as these, is informing the general public of the consequences (though that’s another problem in itself).

                                                                          1. 2

                                                                            Yes, I agree with all of that, and thank you for it.

                                                                          2. 2

                                                                            Maybe companies that aren’t willing to spend the money to build safe software shouldn’t have the privilege of getting engineers to work for them.

                                                                            I see your point, but to me it’s like saying that companies that aren’t willing to spend the money to write proper English shouldn’t have the privilege of getting writers to work for them.

                                                                            They can learn how to write by themselves.

                                                                            I prefer a different approach: turn all people into hackers.

                                                                            1. 1

                                                                              Yeah, I see that point also. But, I mean, writers have historically been more willing to stand up to exploitative labor practices than hackers have… I think there’s a balance to be found, and getting to the right balance requires rethinking some things.

                                                                              1. 3

                                                                                We are just like scribes from Ancient Egypt.

                                                                                Despite the groupthink, we are still at a very early stage of information technology.

                                                                                Just like being a scribe back then, being hackers today does not mean understanding the power and responsiblity we have. But it’s just a matter of time.

                                                                                We will forge the future.

                                                                        2. 1

                                                                          I’m sorry if my post came as provocative! (Maybe my definition of “fishy” – as English is not my native language – is slightly off compared to your definition)

                                                                          Yeah, “I know I could do X instead of clicking, but common user can’t, so let’s walk in their shoes” is a fair motivation. Maybe I just expected the thought to be expressed in the post, given you’ve expressed you’re a programmer. But maybe that’s a silly expectation ¯_(ツ)_/¯ Thanks for the clarifications in the comments here.

                                                                  1. 8

                                                                    One of my favourite things about openbsd is the controlled deprecation and removal of accumulated junk each release.

                                                                    1. 2

                                                                      That’s what I like about Elm language - removing syntax, simplifying concepts, … Refreshing approach to development of anything :)

                                                                    1. 3

                                                                      Great to see other languages steal from Erlang as well :D

                                                                      Here’s my library doing this in Elm: https://github.com/Janiczek/elm-architecture-test/blob/master/README.md

                                                                      And here is a talk on the topic from the Elm Europe conference: https://youtube.com/watch?v=baRcusTHc8E