11 ms·
Programming With Types, Not Tutorials
- bcjordan 13y agoSort of off-topic, but wow, this is a really neat presentation format for tutorials. Love the markdown source[0] and the "open snippet in IDE" features. [0]: https://www.fpcomplete.com/tutorial-raw/5133/cf0de9edd526ea54e3b79358039b3090fbfddd37 https://www.fpcomplete.com/tutorial-raw/5133/cf0de9edd526ea5...
- mightybyte 13y agoThis article gives a nice glimpse into the essence of why modern strong static type systems like Haskell's are such a huge win for development. The type system gives you a way to bound the number of things that you must understand about an API in order to use it. The confidence that we get from having these guarantees makes code reuse orders of magnitude easier in Haskell than it is in pretty much any other language in mainstream use today. All this reminds me of a comment made by a friend of mine awhile back when he was learning Haskell. He said that programming in Haskell feels less like programming and more like putting together a puzzle. I think this article very nicely captures what he was getting at.
- Xophmeister 13y agoThat's definitely how I felt while learning Haskell: Like putting together a jigsaw, which reveals itself when it's done, rather than the usual plumbing and hoping there are no leaks in the end!
- taeric 13y agoSadly, that nice glimpse doesn't really view that nicely. :( It feels like someone showed me an image of a processor and said "see, you just have to line up the pins with where it goes." What could be simpler? If it doesn't fit the pins, it is the wrong processor.
- chowells 13y agoTo be fair, I was starting from approximately "here is where the pins go" in the types I wanted, and "here is how the pins are arranged" in the form of the libraries that could solve it. The complaint I was addressing was that math-heavy libraries that lack tutorials are nearly impossible to use. I provided a constructive proof that it's not hard at all, if you understand the type system.
- taeric 13y agoI didn't mean this so much as a critique of your post. I do believe it serves its target well. I just get annoyed with attempts to elevate it to "a huge win for development." Indeed looking back, I think I picked the wrong analogy. Your post seems to be saying that "without directions on how to put it together, if you know what all the parts of a bike do, you can figure out how to assemble it yourself." There is certainly a fair bit of truth to this. However, this seems to belie a high level of understanding for all for the parts. At least if you hope for a speedy and correct assembly.
- nbouscal 13y agoI think the better analogy is: all the parts are brightly colored, and if you try to put a red part in a blue hole the compiler won't let you. Okay I guess that's not really an analogy anymore, but, you get the point.
- taeric 13y agoSame basic analogy, though. If the parts come such that they only fit together one way, then finding how to get them together can be deduced by looking at them. Falls flat when either a) you don't fully understand the parts or b) you are wanting to try a combination not strictly accounted for in the designing of the existing parts. Problem A is straight forward. Having an in depth knowledge of the "types" in a system has clear benefits. However, not really understanding the types is doable, provided you are strictly in the "assembly" phase of development. I believe that is what this post was about. Problem B is the killer to me. Often "combinations not accounted for" include partial combinations. It is not unreasonable to want to make sure the wheels of a bike spin with the chain before the pedals are placed.
- siddboots 13y ago> ... like putting together a puzzle It's funny how lots of good formalisms, notations, and DSLs all achieve this quality in different ways. In particular, this reminds me of the mathematics of tensors, or Bra-Ket notation in QM. Both of these systems use notation to give each piece of the puzzle a particular shape, so that if you know all of the pieces you can often see immediately how they should fit together. This seems (to me) to be the most important part of designing an API, and the brilliant strength of a good type system is that you get this quality for free.
- eru 13y ago> [...] get this quality for free. Let's say, for much cheaper. Designing a good API in Haskell still requires work---but it's arguably easier to get right than in most other languages.
- ggchappell 13y ago> This article gives a nice glimpse into the essence of why modern strong static type systems like Haskell's are such a huge win for development. The type system gives you a way to bound the number of things that you must understand about an API in order to use it. The confidence that we get from having these guarantees makes code reuse orders of magnitude easier in Haskell than it is in pretty much any other language in mainstream use today. Nicely put. I think that's the clearest statement I've ever seen about why a powerful, expressive type system is a Good Thing. Now, tell me how to get this point across to a programming-languages class for junior/senior C.S. majors, in at most a couple of days, starting 18 hours from now. ;-)
- TempleOSV2 13y agoROFLMAO!! Some nigger fighting God. Just fucken shot an arrow at God! God says...straighten_up later fer_sure et_tu radio it's_hopeless wont_you_be_my_neighbor segway exports I_give_up vengeful what_part_of_God_do_you_not_understand choose_one sess_me is_it_just_me_or I'm_done I'll_be_back how_bout_it you_talkin'_to_me God says... C:\TAD\Text\BIBLE.TXT ommanded Moses. 27:12 And the LORD said unto Moses, Get thee up into this mount Abarim, and see the land which I have given unto the children of Israel. 27:13 And when thou hast seen it, thou also shalt be gathered unto thy people, as Aaron thy brother was gathered. 27:14 For ye rebelled against my commandment in the desert of Zin, in the strife of the congregation, to sanctify me at the water before their eyes: that is the water of Meribah in Kadesh in the wilderness of Zin. 27:15 And Moses spake unto ----- What's gonna happen to them, LOL! God says... adultery unemployment Ivy_league woot church guilty silly_human employee not_good you_think_you_could_do_better eh beam_me_up hippy I'm_not_sure desert Moses insane energy incredibly enough_said to_infinity_and_beyond I'm_in_suspense money run_away don't_count_on_it act what's_it_to_you phasors_on_stun Catastrophic_Success sing sess_me impossible illogical pride debt air_head yeah take_the_day_off off_the_record hooah Tomorrow yeah population come_and_get_me lust absetively_posilutely China these_cans_are_defective fortitude act liberal do_I_have_to I'll_get_right_on_it smile it's_hopeless funny hippy I_didn't_do_it abnormal charity you're_so_screwed comedy furious mundo_stoked ba_ha hilarious no_more_tears end it_gets_better white_trash
- Kluny 13y agoI'm just starting to learn Haskell, reading "Learn You A Haskell..." I didn't realize that Haskell documentation isn't considered very good. Does HN agree with that? Are there any must read documents besides the official ones and Learn You A Haskell to mitigate that problem?
- tel 13y agoA lot of intermediate Haskell material (and advanced Haskell material) is locked up in a series of papers. They're usually well-written, but the intermediate Haskell canon is not well-defined nor is it in a comfortable format; I often find that when I recommend a paper to someone they have a tendency to be turned away... even if it's a tutorial paper not so different from a blog post.
- Buttons840 13y agoIf someone started a blog where they give an approachable overview of all these papers, would that be helpful? Would such a blog be considered rude since many people would read the blog summary instead of the actual paper?
- klrr 13y agoOkey, this is a question to the parent of the comment I reply to. (I couldn't reply to tel for some reason). Do you have any example were the documentation available is only scientific or technical papers? I've been learning Haskell for a year now, and even though I've read some papers due to interest I've never felt like it was the only form of documentation.
- tel 13y agoI'd say that people often reference intermediate Haskellers to a number of major papers like Data Types A La Carte or the Typeclassopedia. The entire set of Functional Pearls are released in academic paper form and provide a really wonderful glimpse into "advanced" Haskell style. You also would probably want to take a look at many of the things that Jeffrey Gibbons or Oleg Kiselyov have written. I could think of others if I dedicated some time to it, but those come up fairly frequently.
- voyou 13y agoIs this a good thing? What the development process in this post appears to involve is a mostly-mechanical filling in of function definitions to match a pre-given type signature; but, if it's mechanical, shouldn't the compiler be able to do it for us?
- mightybyte 13y agoThe compiler is doing a lot of it for us. > Thanks to GeneralizedNewtypeDeriving, I got the three instances I wanted for free via F. A good bit of what you're seeing as "mechanical" is actually the simplicity achieved because Haskell is expressive enough to get very close to the abstractions that we really need. Haskell allows you to decompose problems in ways such that each step along the way is very simple and in many cases obviously correct. Obligatory Hoare quote: > There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies.
- astrobe_ 13y agoHaskell is absolutely fantastic. In C, when I'm given only the prototype of a function like: > int foo(int, int); Even if you tell me it is referentially transparent, I have no idea what that bloody function really does. But with HASKELL, with just the type signature you can write a program that does what you want even though you don't know what the components you used do! Mind/Blown.
- dllthomas 13y agoMy C functions look more like thing_t *find_thing(thing_index_t, thing_t *things); Where my indices are wrapped in a single-element struct so that I get some type safety. You can write bad code in any language. The Haskell things that I miss most in C are the parametric polymorphism and the structural pattern matching. Even so, I've been able to encode some surprising invariants in my C types (with occasionally a little bit of manual help)...
- MichaelGG 13y agoIt really is awesome! If you see a value with this type: (bool -> bool) You know it only has 4 possible names, only 4 things it could possibly do: false, true, not, id. (Ignoring infinite recursion or exceptions.) The list functions are a rich place to explain this to people. (a list -> (a -> b) -> b list) If a declared function has this signature, there's only one reasonable thing it is: map. (It could return the last element only, or an empty b list, but those aren't so reasonable.) What about this? (a list -> (a -> bool) -> a) It'd seem it returns the first item from the list that matches the predicate. Possibly the last item. (And an exception if the list is empty or item isn't found.) Other people aren't as impressed by this as I am, though.
- captainmuon 13y agoI honestly have no idea what all of that does. I'm sure I could work my way through it, but still... in other languages you can get a glimpse of the purpose of a program even if you don't know the syntax. You can tell whether it is a parser, a game, a Hello World, or a web application. The other thing I dislike besides the opaqueness of Haskell is what another commenter described as "mechanically filling in" of code. I get that feeling every time I try strongly typed functional languages. I had the same feeling when I started with C++ and stuggled with `const`. I had an idea in my head, but couldn't convert it to code because the compiler didn't allow it. Instead of helping me, the syntax slowed me down, took me out of the "flow". It rarely, if ever, helped me avoid bugs. Now, I've probably learned avoidance strategies, and rarely have problems with `const` anymore. Haskell gives me that old feeling of programming in a straightjacket, multiplied by 1000.
- klrr 13y agoLearning functional programming is not trivial, especially if you come from the imperative paradigm. Haskell was my first language and I still struggled not to think procedurally in the beginning , and the type-checker refused almost all of my programs. But after a while you start to get less and less type errors, and soon types will be your friend and guide you when writing programs. I have to say though; static types itself doesn't prevent bugs, they only prevent common errors. But if you got an expressive type system like Haskell (or OCaml etc.) you can write well-typed programs. A great example is Yesod[0], which is a web framework completely designed around being well-typed. 0. http://www.yesodweb.com/ http://www.yesodweb.com/ EDIT: Okey, "well-typed" may not be the right term. TAPL calls every program that pass the type-checker well-typed so what I meant is programming written type-safe.
- dllthomas 13y agoIt's a matter of using the types to express meaningful constraints, so that well-typed is more likely to mean correct.
- nbouscal 13y agoIf you don't know functional programming, of course you won't be able to understand functional code at a glance. You wouldn't expect someone who doesn't know imperative programming to intuitively understand imperative code at a glance either. It's not opaque, it just requires learning. Not being able to convert the code in your head into type-safe functioning code just means that you don't understand the code well enough yet. That's not a bad thing about you or about the language, it's just the state of things. Once you gain that understanding, you'll be able to write code that compiles, and you'll also discover that now the compiler is your best friend. Writing Haskell is extremely comforting to me, because I know that the compiler has my back. It's not a straightjacket, it's a guardrail alongside a mountain highway.
- mark_l_watson 13y agobcjordan: sorry, I meant to up vote and my thumb missed, hitting the down arrow. fpcomplete is a nice system for learning. I like the live code and the IDE mode. I signed up for a year paid account, about two weeks ago.
- pekk 13y agoThe idea that you don't need tutorials because of the type system is absurd, another whopper along the same lines as Haskell programs being bug-free. If nothing else, you may need a tutorial to learn to use the complex type system.
- chowells 13y agoThat's why I was very precise in my statement. The great thing about Haskell is that for many purposes, you don't need to understand the math or have a tutorial to use a new library. and But a complaint that you can't use most libraries because they involve math you don't understand and don't have any tutorials? That's one of the silliest things I've ever heard. Note the word "library" in both of those. I was very precise. Library documentation isn't lacking the way some people complain loudly that it is.
- eru 13y agoYes. More documentation wouldn't hurt, though. The type system is more expressive than most other languages', but not that expressive on an absolute scale.
- jlarocco 13y agoIt seems to me that this article actually proves the opposite point that it's trying to make. I have no idea what the program presented is supposed to do, or what problem is being solved, despite knowing all the types being used. I swear the point of Haskell is to make people using Haskell feel smart :-)
- Guvante 13y agoA simpler example would be a basic list operator, given a method you can guess what it does. [a] -> a That takes a list (brackets denote a linked list) and returns a single item. There is a small list of things that this could be. It can't filter or order in any way, since there are no restrictions or functions provided, it can't aggregate for the same reason, that leaves either the first item or the last item. [Yep head and last](http://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+a http://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+a) Looking at that list we can see some other alternatives that I mentioned foldl1 :: (a -> a -> a) -> [a] -> a --Aggregation maximumBy :: (a -> a -> Ordering) -> [a] -> a --Ordering maximum :: Ord a => [a] -> a (!!) :: [a] -> Int -> a --Indexing sum :: Num a => [a] -> a --Aggregating product :: Num a => [a] -> a And if followed along, you will notice all of his implementation points were straightforward. Note that all of this assumes you have very well written APIs that follow this chain of logic, otherwise you can write things like this. second :: [a] -> a second _:i:_ = i It compiles (or would with the default case added) but is rather odd and would throw off this line of reasoning. Similarly by abusing unsafe methods you can do crazy things.
- nandemo 13y agoYour function second is no worse than head or last. I think you chose a difficult example. [a]->[a] or a->a would be simpler, if a bit boring.
- Guvante 13y agoI dunno, I like second being a bad choice, the number of times it is useful are very few. `!! 2` is much more straightforward. In contrast `last` is impossible to do that way and `head` is part of the underlying data structure (as in it is a linked list, so has head and tail) so is a gimme.
- CharlesMerriam2 13y agoAs a long time programmer, this gives an insight into why I avoid Haskell. Syntax matters, in part because it has such an influence on style. When I look at the code, I can't read it. There seem to be poor choices on choosingcasesformultiplewords that dependOnContext but are still unreadable. I can't help feeling that the reserved terms, such as Functor, Applicative, F, and liftF bring the chaos to the thinking process that is reflected in the article. I skimmed it, tried to read it, and still have no idea what the person was even trying to do. This is a language that discourages clarity.
- awj 13y agoWhere are you seeing any discrepancies from camelCase? The only thing I see is that types and constructors (i.e. Functor/Applicative/F) start with capital letters. Also, to be frank, many languages give a false sense of knowledge portability. "As a long time programmer" may not carry you so far into Haskell (or Prolog, or Forth) unless you've seen something else in their paradigms.
- freyrs3 13y ago> Also, to be frank, many languages give a false sense of knowledge portability. This is true, there's a very common psychological bias that people experienced in one domain when encountering a new subject which they find difficult will sometimes blame the new subject matter as flawed or overly complicated instead of realizing the limitations of their own knowledge.
- eru 13y agoFunctor, Applicative, F and liftF are not reserved terms. What makes you think so? They are user defined (or in this case, library defined).
- freyrs3 13y ago> I skimmed it, tried to read it, and still have no idea what the person was even trying to do. The fact that you haven't learned enough Haskell to understand the article after skimming it doesn't make Haskell problematic.
- skywhopper 13y agoPretty depressing if you ask me. You're limited to just plugging libraries together if all you understand is the type system. Hey it compiles and runs without error. Congrats. But does it do what you want? Impossible to say.
- bmurphy1976 13y agoIt takes time man. Understanding is a process. You have to start somewhere. Good for him, it was all greek to me.
- tree_of_item 13y agoThis is a rather frightening article. Why is it considered a good thing to not know anything about the components that make up your program? This seems like blackbox abstraction taken to its absurd conclusion, where programmers simply wire together type compatible components without any idea of what they're actually doing. What does the example program even do? I think this article is one of the best explanations of the visceral reaction some programmers have to Haskell. There's a lot of theory behind Haskell's semantics and libraries, and some people just do not enjoy using something without having any clue of how it works or how it's implemented. Even a hand-wavy naturalistic explanation is better than a dismissive "you don't have to worry about that".
- wting 13y agoAre you implying developers should know the inner details of every library used? Realistically most devs read documentation or Google to get something done. They only dive into the library if the documentation is unclear or something is broken. Reading well written libraries is a good learning experience, but not a requisite to use one. In Haskell a function's type signature is expressive enough to exist as rudimentary API documentation.
- cgibbard 13y agoThe library described in the article gives you a way to take an arbitrary data type, and treat its values as the primitive actions of an embedded domain-specific language (that's what singleton does), and then write interpreters for that language by saying how those primitives should be interpreted (which is what interpret does). All (or at least most of) the control structures for the language come for free, because there's an instance of Monad. This tends to be quite helpful especially in the case where there are multiple interpretations you might be interested in. For example, a graphics library might provide an interpreter that executes drawing primitives using OpenGL to put stuff on the screen directly, as well as one which interprets the same data by manipulating arrays of pixels. Perhaps another could construct an SVG. To do that, you'd provide a data type whose constructors would encode whatever drawing primitives your library supported, things like circles and lines and Bézier splines, and then use the interpret function to define each interpreter by supplying a function which takes a given primitive and says how to carry out whatever actions are needed to be taken to display or render it. (Note: this example is likely a little simplistic, because most of the operations in a drawing library won't have return values, but this set-up allows for such things. You could also make a version where the things drawn also continuously produce values by reacting to user input, allowing for some sort of optional interactivity.) You'd also likely define a bunch of user-facing versions of the primitives which would amount to singleton applied to each of the constructors of your data type, just for the sake of convenience and implementation-hiding. Then you have a library where people can define complex drawings in terms of the primitives you provided, and supply any one of those to any one of the interpreters you defined in order to put it on the screen, or write it out to an SVG file, or whatever. For no additional work, you get operations like sequence :: [Drawing a] -> Drawing [a] from the monad library, for taking a list of drawings and producing a drawing which carries them out in sequence (whatever you've decided that ought to mean via your interpretations, probably stacking them on top of each other), as well as many others. A more interesting example (in that it would involve input as well as output) might be a library for coordinated communication of some sort over different types of underlying network protocols (necessitating different interpreters for the primitive communication operations). Again, you'd get lots of control structures for free, things like for-each loops, and ways to define new bits of a protocol by applying a function to the results of a bunch of smaller pieces of communication.
- mattdw 13y agoMy issue with this is that, quite aside from my lack of understanding of what's going on, the author is constantly professing their lack of understanding of the underlying details. > I still don't know a thing about what F or Coyoneda mean. But it isn't really slowing me down. They're essentially cargo-culting signatures, and while sometimes that can be enough to stimulate proper understanding, I worry that the first time something goes wrong the author will be hard-pressed to solve it. It seems like a useful way to stumble around in unexplored areas; it doesn't seem like a good way to build software you're going to have to maintain and support.
- the_af 13y agoI couldn't maintain or understand the low-level code Java depends on without great effort (I know I could if I devoted enough time, which I usually don't have). Same for low-level libraries for C or any other language. I think the argument here is that -- given that there are no problems with the library; otherwise you're screwed in any language -- type information for Haskell libraries gives you more useful information than docs & tutorials for libraries in other languages. The author repeatedly asserts that he is not scared of math, and would probably be able to understand the libraries he uses if he spent the time. It's just that he doesn't need to.