My understanding is that there is a special link that can be used to link a free version of the page. LWN don’t exactly encourage it, but they don’t discourage it. Could be wrong, been a while since I was a member.
Isn’t that what Pijul is trying to do?
Pijul is coming up with a watertight theory of version control, rather than Darcs patch theory.That said, both use patches, so maybe there will be some cross-polination.
Pijul is doing patch theory. They base it on pushouts.
I honestly don’t see how this helps, but they seem to be trying.
I know they are doing a patch theory, but I was trying to mention that there’s nothing there that tries to implement Darc’s theory of patches. I may be adding more confusion than necessary, though.
Camp has been working on a Coq proof of it.
Sounds like a cool project, but it doesn’t seem to be active anymore. The repo hasn’t been updated in two years and the mailing list is full of spam. Have the changes been merged into darcs already?
It says that users will be informed when they brew update, so that doesn’t seem particularly silent to me? I think the title of this post is throwing more fuel on a fire than necessary.
I used to use fish, but I switched back over to zsh with ohmyzsh. I use konsole as my terminal emulator, as it supports ligatures provided by Pragmata Pro.
Is it really so hard to make a Haskell library callable from Python? If you really need C linkage you can export a C interface from a Haskell program, couldn’t you just call that from Python?
We now have https://github.com/nh2/call-haskell-from-anything, but that didn’t exist in 2013
A serialization library (especially a performance-oriented one) probably shouldn’t be calling a serialization library.
[Comment removed by author]
Does anyone have experience using org-mode in Spacemacs? I tried out org-mode yesterday after reading this comment, but it seems that many of the standard key bindings are in conflict.
Is there a good Spacemacs-specific introduction to org-mode? How about a reasonable way to navigate keybinding conflicts?
I do, but as you said - be prepared to relearn things. I usually get by by using SPC : and typing the command I want, which also shows the key binding. For example it took a while to realise that just t toggles to do status.
I’m gonna be of no help here - I disagree with the Spacemacs philosophy. I think emacs keybindings are great and not hard at all if you invest just a little time in learning them.
Good luck!
I’ve been thinking a lot about a good mobile workflow for org-mode. Right now I’m writing in Markdown because a bunch of IOS apps support that, and using pandoc to convert to org-mode, but that’s not ideal.
I use WebDAV with the MobileOrg app on android, and the normal org-mobile-pull and org-mobile-push. I get webdav through my email provider, not sure how easily it is to get a webdav account though.
I do know that most of the org-mobile stuff works with Dropbox if you’re ok with that.
I wonder if starting with the functor and the free monad is actually helping here - it seems like a lot of work with the potential for pitfalls. Would it be better to start by defining a canonical representation for the effect (r->a for reader, [message] for logging) and then defining the injection from that into Free and then defining the inverse such that Free composition does the correct thing (i.e. doing the “normalization by evaluation” in reverse). Or equivalently, just defining what monadic bind does for our type i.e. not using the Free construct at all?
The main advantage of the Free construct is that we have composition by Functor composition. But that only punts the problem of composition to the interpreter. I’m not sure whether “‘algebraic” as defined here is equivalent to being distributive/commutative, but effects that commute with / distribute over each other are trivial to handle in any number of ways. The difficult part is when they don’t, e.g. when combining try/catch with logging, it’s not at all clear whether we should skip a log message in an operation that’s skipped due to an exception. In mtl-land the order of stacking the monads expresses the order in which their effects will be applied, and it’s cumbersome because it forces the user to actually express that. The linked paper seems to duck the problem by saying that catch is not an algebraic effect. “the denotation of a blurb of code is the composition of the denotation of its pieces” helps us not at all because the denotation of a try/catch and the denotation of a log don’t compose.
Straightforward composition of effects that distribute is pretty trivial (I did so in scalaz-transfigure; I did require the user to use type annotations to express the desired order but that could easily be dropped), and “distributes over any monad” effects can be expressed straightforwardly via a typeclass; I don’t know whether this page represents innovation in terms of doing it efficiently (less interested in that). But I think it’s completely ducking the really relevant question, which is finding good ways to express effects that don’t necessarily distribute.
The problem is how do you know to start with r -> a or [message]? That was not obvious to me, but this gives me a systematic approach to getting there. Which is the linked paper? I’m not seeing a link :)
Sorry, I meant http://gallium.inria.fr/blog/lawvere-theories-and-monads/ .
To me it’s more natural to think “I want a reader, this is r -> a” than to think “I want a reader, this is something that obeys the law (get >>= (λ s → get >>= λ s' → k s s' )) ≃ (get >>= λ s → k s s ). I guess if you have an algebraic definition rather than an extensional one and you can’t see a type that "happens” to be the quotient you want then the technique would be useful - I’m just not convinced that would happen in practice.
I’ve gotta say, if there’s one thing the article made me agree with, it’s the original quote:
The first rule of C is don’t write C if you can avoid it.
This stuff looks tricky! :)
Eh. This guy is just a standards wanker who doesn’t actually offer anything of value. Yes technically a byte is not always 8 bits. But the original title was “How to C in 2016” not “How to C in the Dark Ages.” The only thing I felt was actually worth saying was the bit about ptrdiff_t / intptr_t.
Can we be critical without resorting to unnecessary ad hominem attacks? While the article is certainly towards the more pedantic side, I think it’s important to truly understand what’s going on in any language I work in.
I agree that it’s good to understand a language. But as a critique of the original post, I don’t find this post all that useful. The original provided a decent practical basis for modern C programming. It has it’s problems, and the author responded to those problems as they were brought up, including the legitimate criticisms from this critique. But for a critique that states it “is intended to be constructive criticism,” it sure contains a lot of stuff that doesn’t matter at all.
And I stand by my claim of standards wankery, because he writes stuff like this:
By emphasizing “modern” systems, you ignore both old systems (like the old x86 systems that exposed segmented addressing with “near” and “far” pointers) and possible future systems that might be perfectly compatible with the C standard while violating “modern” assumptions.
The old systems are so old that a modern programmer shouldn’t try for code compatibility with them—at all—unless they have a particular reason to. It’s a waste of time.
And while the possible future systems case is interesting to speculate about, they are so far off that planning for them in this way is an even bigger waste of time. Right now size_t equals pointer size which is 32 or 64 bits. No mainstream hardware manufacturer is going to get around the 32 bit address space with segmentation. For 64 bits we won’t need anything like segmented memory again until our address spaces grow larger than 16,777,216 terabytes.
I’ll admit that I don’t have much patience for standards wankery, maybe because I’ve read a lot of it already, but I would have liked the critique a lot more if he hadn’t spend any time reminding all of us that float technically could be 64 bits.
There are current day architectures where char isn’t 8 bits. For instance the SHARC DSP which has 32 bit chars.
I’m sure you can figure out ways to break it, but it’s a waste of your time (and you need to get a life).
I’m sure it was meant innocently but this really doesn’t read well. Never attack your readers.
Indeed, and I think learning how to break this would be a very rewarding and educational experience. That - to me - is a life.
I made a remark about this on Twitter, but - now that I think about it - it’s probably worth repeating here. The essence of the problem here is that selection is not a homomorphism, and that is leading to confusion. A homomorphism is somewhat of a “structure preserving” operation. For example, I have
length [a,b] = length ([a] + [b]) = 2
length satisfies the homomorphism property, as
length ([a] + [b]) = length [a] + length [b] == 2
The main source of API confusion comes because querySelectorAll is not a homomorphism, though intuitively we expect it to be (I would consider that an API bug).
Being aware of this basic mathematical property goes a long way when it comes to designing APIs.
To understand ScottyT, you’d need to understand ReaderT because that’s basically what it is
I fundamentally disagree with this. To understand scotty you need to understand there is some context you can work in that gives you the computations you need to build a web application. That context is formed by ScottyT over some other monad. You do not need to understand the intricate details of monad transformers, and you certainly don’t need to understand the monads that Scotty was built on just to use Scotty.
You could use Scotty without understanding it, but my point is precisely about understanding.
You’ll thrash around and give up when you need to do something you can’t copy from previous demonstrations.
The point is about learning and equipping people to learn the rest of the ecosystem. I don’t care that somebody could follow along with a prebaked example, type it in, and fire it up and have a web server unless they are somehow learning the language in the process. In my experience, that’s not what results from doing this and it often leads to disappointment.
My co-author’s 10 year old son prefers learning Haskell with our book to the Minecraft modding tutorials he has precisely because he feels like he’s actually learning how things work in our book, whereas the Minecraft stuff is having him type in Java stuff without explaining how anything works. These are commercial Minecraft modding tutorials ostensibly written for children.
I explicitly mention an alternative approach that lets somebody dive into “practical” projects more quickly but it requires things like an in-person teacher to work more than rarely.
I don’t care that somebody could follow along with a prebaked example, type it in, and fire it up and have a web server unless they are somehow learning the language in the process.
That is a hyperbole, and not what I was suggesting. You can teach someone the ability to learn an API from nothing without having them open up the source code and learn how it works. You can teach them how to develop an intuition for navigating the types in Haddock documentation - for example, what does it mean for a function to be an “entry point” (something akin to runScotty)? What do I have to provide this entry point, and how do I produce it?
Then you can teach them a little more about extension points and type classes, and how they can discover these through documentation. Haddock now generates concrete type signatures for instances, so your liftIO example can be discovered if one was to just expand the MonadIO type class and see liftIO :: IO a -> Scotty a, or whatever scotty’s monad is.
I don’t think what I’m suggesting here is giving people a prebaked example, but rather teaching them how to read the maps that are already presented to them, in order to get to their chosen destination as quickly as possible. I see similarities in what we’re suggesting, but my preference is a little more “top down”, whereas you want to approach things from the bottom up.
My co-author’s 10 year old son prefers learning Haskell with our book to the Minecraft modding tutorials he has precisely because he feels like he’s actually learning how things work in our book
Great, and I’m all for this style of learning - I share a common ground with that 10 year old son in that I also like to learn how things work. That said, many people - myself included now - simply do not have the time to learn how things work under the hood if we’re trying to learn something for a career change. It’s also worth noting that the 10-year old son does not have many years of experience building programs in other languages (my assumption could be false). When you already have such a comfort building software in other languages, I think taking so much rigour without letting them play openly could be a quick path to having them put the book down. Of course, these people may not be in your target audience, in which case this point can be dismissed.
I think there is a balance to be reached between exhaustive understanding and tangible results.
Failing to be effective at Scotty because I didn’t understand monad transformers was why I stopped using Haskell for a project and just went back to Common Lisp; and the project I couldn’t finish after a few weeks in Haskell took a few hours — simply because I’m more fluent in CL. It was definitely a stumbling block for me.
To build on what you’re saying, how are you supposed to know how to use an arbitrary IO action unless you know liftIO? You can’t so much as print something without knowing to use liftIO when you’re in ScottyT.
It turns into turtles(turtles := cargoCulting) all the way down if you follow this unconstructive method of teaching the language.
I had a really good experience “cargo culting” Scotty using this post as a guide. It said use “liftIO” for one thing, so whenever I ran into something like that, I used liftIO! And after a while of using it (and finding lots of places I couldn’t use it, and figuring out why), I understood what it does. But that’s just how I learn, I know it doesn’t work for everyone.
You were already a programmer to begin with right?
We’re writing for a larger audience than just experienced programmers and even among those I’ve seen many get frustrated with not knowing what’s going on. I actually just had someone in IRC mention they’re happier with the book than LYAH because they felt like they weren’t being shown what was actually going on.
Your experience isn’t implausible to us at all, but that’s part of the reason we wanted to write this post, many programmers take their experiences for granted as representing what most learners will experience if they attempt to learn the same concepts.
I appreciate the sentiment here, but it seems to forget two points:
libxml2 is complete. Look at the release history, there hasn’t been a major feature added to the library in years despite it being one of the most popular packages. 98.96% of hosts with popcon installed have libxml2, yet most of the work put into it is security fixes and OS/400 compatibility.
Yes fully agree. Half of the stuff I have on github is there mostly cause why not. I have zero plans to support it, or even finish half of it. Most of the time you get further into the weeds and realize, well I really don’t need this that bad for the effort it will take to do this right. Or you decide to backburner it and give it a think because you don’t feel you understand the problem well enough yet.
Also I worry about this idea that software is never finished. I feel like we’re in a weird perpetual loop or maybe a rut just spinning our wheels and not going anywhere with all this churn going on. I want done tools. Or tools that do the thing they need to well enough they are effectively done. All this constant wheel reinvention is maddening.
I hear you, on that, and I see both sides. I think software is at the intersection of tool and art. One should strive to reach the goals that are reachable, and covering the same ground every decade is beyond frustrating.
My personal pet peeve is self-describing data formats, which, with the amount of ire they have always drawn, surely would not keep being reinvented if they didn’t fill a real need… The lack of obvious progress is quite demotivating.
Just to balance that with a less depressing example, if one looks at language design, there have been enormously many new ideas, and everything’s being explored at once right now, and it’s kind of wonderful the sheer variety that exists. If languages are ever a “finished” problem, computing will be in a much better state than it is today.
On the gripping hand, I don’t actually think that stability in software is always a sign of it being good. I get frustrated with tools like bash, which does get its job done, and if it’s had any movement in the past decade I haven’t noticed, … but I absolutely hate using it. I wouldn’t view that as a problem the authors of bash are obligated to address; clearly, they’ve made the artistic statements they have to make, and it’s unreasonable to expect them to have more indefinitely. But that leaves room in that area for somebody else to say something new.
I will admit, self describing data formats to me really probably should end up being a lisp or maybe a scheme, just evaluate/execute the data and get what you want out of it. But I’m a weird person that way. >.< I’ll admit I haven’t thought this through that much.
And agree on languages, I’m not saying stop developing new languages to be sure, nor do I think herding all those cats will be possible to ever do. Take the recent Haskell AMP change. Language theory in the past decade has changed how we view things, and for the better in my opinion. Onward and upwards in that regard, even if it is painful. I hope for more pain in getting to dependent types in Haskell. But I don’t consider languages to be in the tool category.
As for bash, I’ll agree that it sucks (joking here), but i’m a zsh heathen so of course i’d say that. But more to the point, I would consider most shells to be “done” at this point. bash for example does keep piling more stuff on, as does zsh, but fundamentally, they tend to still serve their original and by this point ancient root purposes of a command shell and interpreter. Keeping backwards compatibility here is a required feature.
For it not being modern, sure I don’t disagree but replacing it might mean a lot of false starts and we might end up back where we started. If whomever decides to create a “better *sh” doesn’t look at the plan9 shell, tcsh, csh, ksh, bash, zsh, fish, i’m sure I missed some unicorn shell or other, I think we’ll just end up where we’re at, with 40% solutions that in the end leave a bitter taste.
I know I feel that way about some new things recently. That or maybe I’m just old now and need kids to get off my lawn. :D
But the more I look and read papers from the 60’s, 70’s, and so on, the more I realize we reinvent the same crap over and over again. More often than not poorly, malign say APL all you want but it is a great language and there is a LOT to learn from it that directly relates to our problems today.
Heh - I’ve thought it through quite a lot. I don’t feel up for giving the elevator pitch of my pet project right now, but the thing about using a procedural rather than a declarative description of data is that you lose the ability to operate on it with tools that know some things about its structure, without knowing everything - for example, “this is an array and here is a comparator for its items; sort it”. Anyway, I think solutions are possible.
Languages are indeed definitely much more art than tool, but at the same time they need to work, or they’re useless. The thread at first wasn’t distinguishing between types of software - “finish your stuff” doesn’t say what type of stuff - and I’m glad it has now become more nuanced. :)
I agree with you also that replacing things doesn’t automatically make them better. This is why I feel the art analogy is so strong. There have been periods in art history where everything got very cliquish and, despite there being a lot of people making things, they were all making more or less the same thing, over and over. Somebody has to actually have a new, better idea, at some point. And that almost always has to be informed by what has gone before, or it’ll just restate what’s already been said.
So, yes, I was specifically not making a call to arms to rewrite bash. Not unless somebody feels they understand the problem space and the solutions we’ve seen so far, at least! I feel like in many ways the Lisp-based shell on Genera was better than anything one can easily run today, but I also don’t think it would be useful today. It’s a hard problem.
And yeah, I am sure I’ve read different things than you but I make it my business to read papers on historical innovations in computing. I completely agree that a great deal of “new” work isn’t.
i think a lot of it ties in to the other point the article was making, which is to define the scope of your project so cleanly and narrowly that it is self-evident when it is finished. that project can then be used as a clean, reliable building block in other software. i have to admit that it is a very attractive ideal to aim for, even if i seldom get there in my own stuff. (in large part, because the tooling ecosystem encourages developing projects as monoliths; developing, versioning and testing parts independently can get fairly messy.)
I agree that having to use grep to find packages is tedious, but do note there are alternatives. One is nox - which provides a cache and a nicer interface to search. The other is using the web based search page - but that does impose a bit of a context switch.
Georges Dubus actually did reply on Twitter, pointing out nox. I’ve updated the story to reflect that. Thanks for mentioning these alternatives.
I read the “Simple Easy!” paper long ago, but this presentation is quite a bit easier to digest w.r.t. the plain nuts and bolts of your bidirectional type checker. Thanks for writing it up, Danny!
Yeah, I didn’t mean to but I guess I ended up with a nice presentation of Simple Easy!
I’m still entirely dissatisfied with how bindings are handled :/ Since it’s like all the warts of DeBruijn with some of the quirks of explicit names with just a dash of odd HOAS tossed in. Variables are hard, we should just use SKI.
Ha, yes. I found that weird in SE! too, otoh it also serves as an example for how to do non-trivial work under each binder style. Write a final section using Bound and you could write a new post comparing the whole farm of variable binding techniques.
Fwiw, it is non-trivial in Bound to do type-checking with contexts and working under binders. Larry Diehl has learnt some techniques for doing so in the course of using it in Spire, but it is extremely difficult.
Ah, I forgot about that. Ed once pointed me at Initial Algebra Semantics is Enough! as having tricks to get around that, but I never get my head around how that might work.
I should do this.. Mostly because I don’t think I’m smart enough to scale the current scheme to what I want to do :)
Before you do, make sure it actually makes sense to. Can you get away with just using rrdtool instead?
There aren’t really a ton of useful papers out there. I’d suggest looking at OpenTSDB’s stuff, then talking to Benoit and asking him what he thinks his mistakes were. If you have friends at big companies, go ask them what they did. Make sure you understand what’s going to make explode your space, and try to make the API so that it’s hard to do that. Arbitrary tagging sounds like a good idea, until you realize that adding another tag to your key makes your storage for that key combinatorially more expensive.
If your stuff is totally in memory, I wouldn’t worry too much about how you’re going to compute your results. If you decide to make a distributed one, you’ll probably eventually want to support materializing views on write as well as on read–you shouldn’t need to do this for in-memory time series unless you start doing really sophisticated aggregation.
Make sure it actually makes sense.
I learn through building, and in this area I’m interested in building up my knowledge of TSDBs. I probably am not looking at anything that I’ll even put in to production for my own purposes - just a bit of hobby work.
Thanks for the reply - all good leads!
No idea, my guess would be that if you could see what he broke from OpenTSDB1.x when switching to OpenTSDB2.x, that would probably be a good first-order heuristic.
When he was talking about caching:
One thing that I don’t yet understand though, is how this plays out with memory usage. For example, if I’m caching from my root element, this presumably means every single view that makes it to the browser stays in memory… forever. That seems pretty bad! One easy fix is to annotate my rendering with explicit “don’t cache this” points, but everytime I find a model that requires the programmer to annotate it for performance, my heart sinks.
was he talking about within the browser, or within the haskell code? Haskell doesn’t do any caching I don’t believe…. and if it’s the browser, then there’s nothing you can do about that anyway. Comments, his blog needs comments!
He’s thinking about applying this to compiled Javascript, so he means in Haskell-in-Javascript-in-Browser :)
I’m right here :) As tel mentions - this is compiled-to-Javascript Haskell with GHCJS. While Haskell doesn’t do automatic memoization (loosely speaking), with this approach we do have a problem that the root node (e.g., the <body>) tag will always be present. This means that with my approach, it always remembers how it drew all previous incarnations of the page. It’s that that I’m worried about.
As someone who’s building a React-like framework (though entirely in Haskell), this is something that is really tempting to me. I completely agree that CSS is not composable and akin to a huge soup of globals. Does anyone know if there’s been any more discussion on this topic? I’m most interested in knowing how well a browser would deal with something like this.
We looked into it briefly for our project. We actually concluded that we’d rather stick to SASS, but try to educate our team as to how to write maintainable CSS.
I still find the approach interesting. It pushes ReactJS even more into “immediate mode rendering” territory.
I think css is more of a dev problem then a tech problem. The browser can handle the work efficiently, that’s probably why it’s never needed to be changed. The problems come when devs need ways of keeping tracks of changes to all those globals without stepping on each others toes.
The battle has been won!
It’s always been slightly weird to me that all these patch algorithms seem to operate at the level of individual lines of text, yet programs are not semantically broken up into lines.
Fortunately for VCS systems, programmers tend to write programs so that semantically separate chunks are on successive lines, so these merge algorithms do the right thing most of the time. But wouldn’t an algorithm that was capable of breaking patches on lexical boundaries for the programming language in question give better results?
AFAIK even semantic merging of XML documents is still a hard problem being researched in academia. Perhaps with some more advanced AI, we’ll eventually get there…
Yes, but it would no longer be a general difftool; you now need to know which lexer to use. Eg Git supports choosing a difftool based on file extension.
Given that different versions of the same language can have different rules, you will soon have a difficult task maintaining a list of known digging tools ?
Sure, but at the same time we’re currently in a situation where whether a merge is correct can depend on the indentation choice the programmer made. That’s not exactly an ideal situation either!
If your comment means “why don’t the tools know about the structure of the language”, the problem is - languages change. Syntactic constructs get added and removed, so the parser for code today may not parse that same code a year down the line. Thus baking language specific constructs also requires baking a lot more information in, and potentially dealing with diffs between two different schemas of ASTs, rather than just two different ASTs of the same schema.