1. 3

    Maybe this will convince me to restart my LinkedIn account. It does seem to be a bit of a career hindrance not to have one.

    1. 5

      Wait until you start getting all the recruiting emails before you decide what’s more of a hindrance :)

      1. 4

        That and LinkedIn’s own un-blockable emails are what led me to delete my account in the first place 🙄

    1. 4
      vnoremap < <gv
      vnoremap > >gv
      

      gv is pretty nifty.

      1. 1

        That is a top tip indeed!

        1. 1

          I’ve been 20% happier since I discovered that. Wish VSCode’s Vim emulation allowed me to do the same.

      1. 20

        Thanks to all the Monad’s tutorial and hype, when I first learned Haskell, a few years ago, it took me a few months to accept that I had understood Monads at the first glance.

        All those tutorials were just confusing. I was all thinking “what am I missing? it seem so simple! why nobody explains what I’m missing?”. I was missing nothing.

        A Monad is simply a wrapper. You have a function to wrap a value (return) and a function that applies to the wrapped value another function that returns a different wrapped value (bind). That’s it.

        1. 11

          Completely agree with you!

          See the eightfold path to monad satori from What I Wish I Knew When Learning Haskell:

          1. Don’t read the monad tutorials.
          2. No really, don’t read the monad tutorials.
          3. Learn about Haskell types.
          4. Learn what a typeclass is.
          5. Read the Typeclassopedia.
          6. Read the monad definitions.
          7. Use monads in real code.
          8. Don’t write monad-analogy tutorials.
          1. 2

            Thanks for this list. Someone on my team recently read and shared a “Monads are like Burritos” blog post. The post made several dubious analogies. The effect was that people felt like they understood Monads. In fact, they did not. This is worse than not understanding them and feeling like you don’t understand them.

          2. 7

            Seriously. People act like the concept is so complicated and it really isn’t. I definitely knew what monads were for a long time before all the elaborate metaphors muddled my understanding. So far I’ve gotten the most mileage by illustrating how to convert procedural code to “math style” single expression functions, and rolling from there.

            1. 1

              People correct me if I’m wrong because I’m not a Haskeller. I do keep reading these monad things and getting confused about it. One person told me it was basically just imperative programming in a functional language to make things happen in a certain order. I haven’t had anyone attempt to corroborate or refute that. Maybe just one. Your statement sounds similar.

              It also reminds me of SSA form a little bit in how you describe it.

              1. 15

                I will corroborate that as a partial explanation. And it should remind you of SSA form, since it helps accomplish similar things. I think that’s a confusing place to start though, because people tend to ask why functional languages don’t just run things in a certain order anyway. And they do, take printNum( readNum() + 1 ), this will clearly read a number before trying to print the number.

                Instead, assume we have a VM that only understands simple “math style” functions like:

                f(x) = expression
                

                Such as:

                square(x) = x * x
                

                So yes we could write:

                main() = printNum( readNum() + 1 )
                

                But we could not write:

                main() = print("multiple"); print("expressions"); print("in a sequence")
                

                That is, the VM does not implement multiple statements in a function, it expects only a single expression. Why not? Ignore that for now. This code will work though:

                main() = printStage1()
                printStage1() = printStage2(print("multiple"))
                printStage2(x) = printStage3(print("expressions"))
                printStage3(x) = print("in a sequence")
                

                See how that would work?

                That’s tedious as hell to write though. Humor me, and now lets write it with lambda expressions. Lambda expressions are function values, i.e. these two definitions of main are equivalent:

                main() = print("hello world")
                main = λ() -> print("hello world")
                

                Notice I’m using main() = to define a named function, but just main = with lambda. This is exactly identical to the following javascript:

                function main() { print("hello world"); }
                main = function() { print("hello world"); }
                

                So we can rewrite our program like so:

                main = printStage1
                printStage1 = λ() -> printStage2(print("multiple"))
                printStage2 = λ(_) -> printStage3(print("expressions"))
                printStage3 = λ(_) -> print("in a sequence")
                

                Now lets inline some things, one step at a time:

                main = λ() -> printStage2(print("multiple"))
                printStage2 = λ(_) -> printStage3(print("expressions"))
                printStage3 = λ(_) -> print("in a sequence")
                
                main = λ() ->
                         (
                           λ(_) -> printStage3(print("expressions"))
                         )( print("multiple") )
                printStage3 = λ(_) -> print("in a sequence")
                
                main = λ() ->
                         (
                           λ(_) ->
                             (
                               λ(_) -> print("in a sequence")
                             )( print("expressions") )
                         )( print("multiple") )
                

                We now have a strategy for compiling a sequence of expressions into a single lambda expression, that returns the result of the last expression. Notice that I used underscores for the lambda args, because their result was unused by the function. But what if our program uses variable names? These are equivalent:

                main() = {
                  n = readNum();
                  printNum(n);
                }
                
                main = λ() ->
                         (
                           λ(n) -> printNum(n)
                         )( readNum() )
                

                Hopefully you can now see that we could write a compiler that converts normal imperative code with variable assignments and so on into an unreadable chain of simple lambdas.

                So why would you want to do that? Well, if this was a language we were implementing, we can add imperative syntax to our language without actually extending the VM. Our language interpreter can pre-process the code into simple lambdas, then the VM only has to know how to execute simple lambdas. That’s neat.

                It also lets us make radical simplifying assumptions, just like SSA. Function calls can be evaluated in any order, as long as all its arguments have been evaluated first, just like SSA. But the way we’ve done it so far makes every line dependent on every previous line. So now lets split = into = and <-, where = denotes a weakly ordered assignment, and <- denotes a strongly ordered assignment.

                main() = {
                  a = 7
                  b = 2
                  x <- readNum()
                  y <- readNum()
                  _ <- printNum(a / x + b / y)
                }
                

                We don’t actually need to create a new lambda until we hit a strong assignment. So this simple lambda code is equivalent:

                main = λ() ->
                         (
                           λ(a, b, x) ->
                             (
                               λ(y) -> printNum(a / x + b / y)
                             )( readNum() )
                         )( 1, 2, readNum() )
                

                Okay but what if we screwed up and wrote this:

                main() = {
                  a = 7
                  b = 2
                  x = readNum()
                  y = readNum()
                  printNum(a / x + b / y)
                }
                

                Which would compile to this:

                main = λ() ->
                         (
                           λ(a, b, x, y) -> printNum(a / x + b / y)
                         )( 1, 2, readNum(), readNum() )
                

                If functions can be evaluated in any order, will x or y be read first? It’s undefined. Either readNum() call could run first. You shouldn’t be allowed to weakly order things like IO. That should be an error. One way to do that is to give readNum a type, that insists its return value must be strongly assigned. But readNum should also be ordered with respect to printNum, and anything else that does IO.

                So lets define these functions with a special return type that says they are both IO:

                readNum(): IO(Number)
                printNum(n: Number): IO()
                

                This IO wrapper type must be strongly assigned, and the result of its assignment will be its inner type. That is, these are basically equivalent:

                x: Number = 1
                x: Number <- IO(1)
                

                That’s the IO monad.

                The strong assignment operator <- is called bind. A monad’s bind function takes a function, and returns a new monad, that represents the result of applying the function to the monad’s inner value. Using our typed readNum and printNum, our program looks like this:

                main() = {
                  a = 7
                  b = 2
                  readNum().bind(
                    λ(x) -> readNum().bind(
                      λ(y) -> printNum(a / x + b / y)))()
                }
                

                If you’ve ever written node.js before, you might be thinking hey wait a minute, that’s just an IO callback! Honestly yeah, pretty much. But with strong typing and syntax sugar. We can write this:

                x <- readNum()
                y <- readNum()
                printNum(x + y)
                

                But if we write this, it’s a type error:

                x = readNum()
                y = readNum()
                printNum(x + y)
                

                Why? Because the + operator has the type signature Number + Number, not IO(Number) + IO(Number). Even if + was defined for IO(Number), printNum still takes a Number, not an IO(Number). The type system forces us to bind properly.

                So now our VM (or compiler) can treat all assignments as weak, because we’ve implemented strong assignments on top of weak assignments and lambdas. Normally assuming all assignments are weak by default would make the language hugely error-prone to use. But the IO functions all return an IO monad, so the type system protects us. Constrast with a conventional imperative language, that must assume all assignments are strong unless it can prove otherwise.

                Naturally the weak assignment strategy opens up a lot more opportunities for certain kinds of optimization. Haskell still hasn’t taken over the world though, cause there are a lot of other opportunities for optimization, like hand writing vectorized assembly. That kind of thing is harder to do in Haskell than e.g. C.

                1. 3

                  That’s one of the ways Haskell uses monads, but IIRC (and I probably don’t RC), that’s driven more by Haskell’s lazy evaluation than a fundamental property of functional languages.

                  A more general use case of monads is the Maybe monad, which lets you control for nulls. If a function could return an integer or a null, you instead say its return value is Maybe Int. Then the type system can enforce that anything that calls that function handles both the integer case and the “null” case.

                  1. 2

                    I do keep reading these monad things and getting confused about it.

                    Monads are mathematical structures. They have nothing to do with computer programming whatsoever. In fact, monads are so ridiculously general compared to most other mathematical objects that there is no way they could serve a concrete purpose for non-mathematician standards. So the first thing monads are not is “something you use”.

                    Theoretical computer scientists (read: mathematicians) discovered [0] that you can “give a semantics” to a higher-order [1] strict [2] language in which “types” are denoted by “objects in a category C”, and “a computation that produces a value of type B from a value of type A” is denoted by “an arrow A -> TB”, where T is “a strong monad over C”. The tl;dr of all this [3] is that monads are “something intrinsic to the very structure of the programming languages we use”, just like the Earth’s gravitational field is “something intrinsic to the very structure of the world we live in”. You don’t need a mathematical model for it to exist, although it is nice to have one for some purposes.

                    However, Haskell is a lazy language, so it is intrinsically comonadic rather than monadic. (Again, [3].) And, while Haskellers like their lazy language overall, they also want the sequential structure of their effects to be more like what strict languages have, because lazy effectful computations are insanely hard to reason about. So you could say Haskellers have monads in their standard library because they don’t have it in their core language.

                    I have made essentially the same point elsewhere.


                    Footnotes:

                    [0] As opposed to “created”, like operating systems, word processors or computer games are.

                    [1] Having procedures as first-class values, e.g., Lisp, Python, Java, ML, Haskell.

                    [2] Reducing arguments to a normal form before they are passed to a function, e.g., Lisp, Python, Java, ML, but not Haskell.

                    [3] Lots of details omitted. It doesn’t really matter what any of this means anyway.

                    1. 1

                      Your distinction between “discovered” and “created” seems to presuppose Platonism, which is a rather contentious issue in the philosophy of mathematics. A Formalist would say that math is indeed created, and that while the implications of a mathematical system may not be known for a long time, math is still a product of a human mind.

                      1. 1

                        I’m by no means a Platonist. I’m just saying monads weren’t invented for this specific purpose. Noticing connections between seemingly unrelated mathematical theories happens all the time.

                2. 6

                  Explaining monads to programmers is like explaining commutativity to accountants.

                  1. 4

                    Yep. This is why I shifted to trying to teach people to understand the concept of data that obeys laws. That’s the real issue: they see “monad laws” and they freeze.

                    1. 7

                      Probably easier for statically typed OOP people to just hear interface. A monad is a kind of interface for some generic type with a constructor and an aggregate/flatmap where the returned generic is the same type as the input.

                      I think most of the struggle in learning that its just a type with a bind and return is people worry about teaching the math behind it. This is a bad idea. If you’re going to teach math, teach math, and if you’re going to teach programming teach programming. You don’t need to understand the abstract backbone to understand that you can use this thing to manage side effects.

                      1. 1

                        What exactly is a nontrivial data structure, if not “data that obeys laws”?

                      2. 3

                        This, a million times over. When I learned about monads in university, the concept was simple and intuitive and I recall just “getting it.” A couple years ago I decided to learn Scala (after a decade of using imperative languages), and a lot of the tutorials made a big deal about monads and tried to explain them in the most obtuse manner, using all kinds of computer science terms and references. For a while I questioned whether I had actually ever understood monads.

                        1. 1

                          I’m in the process of learning Haskell myself right now and I feel myself slowly coming to this same conclusion. I think part of the reason they seemed complicated on the surface, for me at least, is due to how heavily they are used in so much Haskell code out there.

                          Also because of the abstraction-driven nature of Haskell, I’m always aware that there’s (potentially) a lot happening behind a small operator or function so as a beginner I assume there’s a lot of magic happening that I just don’t understand yet. Couple that with terms for these concepts that are rooted in mathematics (and thus unfamiliar with your average dev, like myself) and you get a recipe for assuming there’s always more to understand.

                          1. 1

                            I think it really took this video for that to get across to me. This whole time I thought I was still missing something. It turns out I use Monads all the time!

                          1. 11

                            This article has a very low quality: it reports on two not interesting facts (retrieving code via http and loading a DLL from current directory). Why is it upvoted so much?

                            1. 14

                              Two relevant points at least: (1) an unverified binary is downloaded and installed and (2) on Windows outdated and likely exploitable versions of OpenVPN and OpenSSL are installed.

                              Then there’s the other more trivial stuff in the article that may or may not be interesting.

                              Despite the abrupt nature of the article, it seems worth talking about.

                              1. 4

                                Yeah, I’m kind of appalled that the author completely glanced over the setup step where you download the script asking you to send your password over an unsecured connection. Forget about a man in the middle attack that switches the script, all you need is to log the HTTP requests and you get the user’s password.

                                1. 4

                                  They seem to stop because “they couldn’t be bothered” right where things could be about to get interesting. Which is fine ofc, that’s their prerogative, but it leads to a largely uninformative article.

                                  1. 1

                                    Yeah, something has got to be wrong here. How can an article have 49 upvotes but not a single comment in its first 13 hours?

                                    1. 8

                                      It’s an interesting find but not super engaging. It’s gross incompetence with very much not industry best practices. There isn’t much to learn from this other than “don’t write sketchy code”.

                                  1. 2

                                    Couldn’t agree more. Had one of these for work for a couple years, was really happy with it, looked forward to putting off the upgrade cycle as much as possible. Unfortunately managed to screw up the screen with a bad screen wipe (long story on why the company would provide screen wipes capable of removing the coating of a MacBook, but that’s another story.)

                                    The “upgrade” I got (bigger SSD, discrete GPU, a newer CPU) sucked: the screen would flicker when it randomly switched between the integrated and the discrete GPUs, whatever OS X does for deciding when to switch to the discrete GPU would be triggered by IntelliJ running for a few minutes, which in turn made the computer become hotter on the same loads. Finally. capital sin for a laptop: the battery life went down by a solid two to three hours. All in all, it was a downgrade by every measurable metric.

                                    Now, between the new butterfly keyboard (which I’ve had to use on occasion and find appalling) and the “touch bar”, I’m really considering buying my first non-Apple laptop in over half a decade.

                                    1. 2

                                      I’m interested in how the transition to Wayland goes. I’ve heard that there are still some problems with some mainstream graphics cards and older games that rely on Xorg…

                                      1. 4

                                        Wayland is the default on Fedora, and has noticeable performance benefits (it feels like 60FPS). The only problems I’ve noticed are Chromecast not working and color picker picking black all the time. This and memory bloat, but that might be a Fedora issue, I have to compare with regular X gnome.

                                        1. 2

                                          games/anything else. Non GTK+ software ends up running under xwayland… I just don’t understand all this wayland-fever

                                          1. 10

                                            I just don’t understand all this wayland-fever

                                            A drowning victim will reach out for anything. X11 is not a nice stack to develop on.

                                            1. 1

                                              Like, directly? Maybe not. But even xlib is not bad and most people use much more abstract things than that :)

                                              1. 3

                                                Just curious, what would you consider a worse UI dev experience than xlib?

                                                1. 7

                                                  Trying to build a rich application UI in HTML5+CSS3 ;) (which is a big part of $DAYJOB)

                                                  Seriously, though, it depends on the kind of UI you’re building and other such things.

                                            2. 7

                                              There’s a few reasons why I’m bullish:

                                              1. Improved security (X was designed for another era)
                                              2. Simpler pipeline from calling an API to draw something to it actually displaying
                                              3. Fractional HiDPI support: I hate having a high resolution laptop and connecting it to a “normal resolution” 30in monitor. Everything is out of whack

                                              Last but not least: it might weed out some of the ancient UI libraries that people are still using for new software. I hate to see old software go to waste, but a more consistent desktop experience would be nice.

                                              1. 2

                                                Xwayland will be supported for a long time. The only software that will truly go to waste is stuff that relies on security holes access to everything all the time: utilities for global keyboard shortcuts, screenshots, etc.

                                          1. 20

                                            Also from release notes: “Python 2 is no longer installed by default. Python 3 has been updated to 3.6.”

                                            1. 4

                                              This is a step in the right direction. I’ve been using Python 3 for all my projects in the last few months and I have to say, outside of whatever performance differences there might be (haven’t noticed them yet) the transition has been smooth, and things like MyPy are great.

                                              1. 4

                                                On that note, I got 10x speedup with PyPy which now supports Python 3.5. I’m super impressed, but it only works well on server-type workloads.

                                            1. 14

                                              Another issue about typing git is that sometimes I type gti, so I have installed this beautiful application http://r-wos.org/hacks/gti

                                              1. 3

                                                I just type g, because alias g=git. Since it’s one of the most common commands, it deserves to be just one letter.

                                                1. 4

                                                  I do that as well. Also, l=ls, m=make. Then there are shortcuts like gl for git log, gd for git diff, st for git status, gup for git pull --rebase, etc.

                                                  1. 3

                                                    Ohh… my git aliases are actually “vim-like”: https://github.com/myfreeweb/dotfiles/blob/master/dev-base/gitconfig

                                                  2. 1

                                                    Seriously. Why bother with ls when you have git? Counting command frequency, my alias gs has over 20 times the usage of ls.

                                                    alias gs='g status -sb'
                                                    
                                                    1. 3
                                                      alias l="tree --dirsfirst -ChFL 1"
                                                      alias l2="tree --dirsfirst -ChFL 2"
                                                      

                                                      etc.

                                                      1. 2

                                                        That would blow up my terminal. I have a very… flat… organization strategy. Really even using ls in my home dir is useless without a glob. ?

                                                        And my home dir is a git repo anyway.

                                                  3. 2

                                                    ROFL, that’s hilarious. I wish there was an equivalent thing I could install so whenever I press “Esc” on my keyboard I get an annoying animation (I’m trying to teach myself to use Caps-Lock as an Esc key, seeing as I’ll probably be doomed to buy one of the new Macbook Pros with the stupid touchbar soon.)

                                                    1. 4

                                                      Why bother with an animation? If you really want to stop hitting Escape, buy that Macbook :-P

                                                      More seriously, and in case Escape is important because you use Vim: I have grown very fond of :inoremap jk <Esc>. Perhaps that’s of use to you, too?

                                                      1. 1

                                                        As someone who uses jk repeatedly to find where they are on screen when i get lost, that might just kill me. But ctrl+c will exit you from insert mode in vim. As will ctrl+[. Both of which have been really nice when using a touchbar mac.

                                                        1. 1

                                                          In truth, jk doesn’t work for me, either, because I type a lot of Dutch. I use nj, instead. It rolls nicely off the fingertips. I have also heard people recommend jj.

                                                      2. 3

                                                        it doesn’t have to be a burden, I swap esc and caps lock for better ergonomics.

                                                      3. 1

                                                        There’s also sl: https://github.com/mtoyoda/sl

                                                        1. 2

                                                          Of which I’m a huge fan. Also contains criticism of gti, debian and systemd.

                                                          Sorry for linking to a comment on a different platform, but in this instance, I don’t want to waste vertical space here.

                                                      1. 2

                                                        I like the idea behind the project, but the article is odd because it shows JavaScript code and not C code. I’ve already seen and done this style in JavaScript. I would like to see it done in C.

                                                        That said I read some of the C code in the repo and it seems pretty nice. It would be nice if the two were more closely connected.

                                                        1. 3

                                                          Then I’ve got something you might find interesting: the old manuals for the LCC-Win32 IDE, which contain a really nice overview of all the systems the author wrote or modified (from the C optimizing compiler to the resource editor and Wedit, the text editor.)

                                                          https://docs.google.com/document/d/1_S7gv6UGLAKuo9g1tNoNbU2OR_5DBYEdquvYeqgkPMk/edit?usp=sharing

                                                          I remember reading these docs about… 15 years ago? (holy crap!) and they were a great introduction to a lot of topics. The newer versions of the compiler don’t include these docs anymore, which I consider a shame.