[HN Gopher] Introduction to Haskell Typeclasses
       ___________________________________________________________________
        
       Introduction to Haskell Typeclasses
        
       Author : ingve
       Score  : 111 points
       Date   : 2022-04-27 07:59 UTC (15 hours ago)
        
 (HTM) web link (serokell.io)
 (TXT) w3m dump (serokell.io)
        
       | da39a3ee wrote:
       | Wouldn't it be helpful to use the word "interface" in the article
       | (and other docs) since that's basically what they are known as in
       | other languages (or "trait" in Rust and Scala). I'm sure we can
       | have a really long thread on the difference between these
       | concepts in different languages but wouldn't it help beginners to
       | be told that those are more or less the same thing?
        
       | prezjordan wrote:
       | I really enjoyed this, thanks! I've been writing OCaml a lot and
       | wish it had the expressiveness of `instance Eq Pokemon where`.
        
       | somewhereoutth wrote:
       | Would it be fair to say that typeclasses are a formalisation of
       | _ad-hoc_ polymorphism? With all the good and bad things that come
       | with that.
        
         | dboreham wrote:
         | Pretty much.
        
         | mumblemumble wrote:
         | I may be way off on this, but I like to think of them as a
         | bridge between ad-hoc and parametric polymorphism. Or maybe an
         | ad hoc wolf in parametric sheep's clothing.
         | 
         | Functions and types that refer to typeclasses are
         | parametrically polymorphic insofar as they don't refer to a
         | specific implementation of that type. This is quite different
         | from run-of-the-mill function overloading, where you must
         | supply separate implementations for every set of types you want
         | to support.
         | 
         | But, unlike how parametric polymorphism works in OOP, late
         | binding is not an option. At the use site, the typeclass
         | implementation you want to use must be statically resolvable.
         | In that respect, it does behave like function overloading.
        
       | HelloNurse wrote:
       | Very well written, but an introductory tutorial shouldn't ignore
       | fundamental difficulties like multiple conflicting instances of
       | the same typeclass for the same type.
       | 
       | Your example would be a good fit, since Pokemon can be
       | "naturally" ordered by number, by name, by which one has more
       | types, and in infinite other ways.
        
       | _query wrote:
       | If this post got you interested in learning more about Haskell
       | and you want to see type classes in some real code, a great
       | starting point for Haskell is IHP :)
       | 
       | IHP is a new Haskell framework with a focus on actual building
       | applications. Imagine the productiveness of rails combined with
       | the typesafety of Haskell.
       | 
       | It's now already the biggest Haskell web framework, we just hit
       | 3200 GitHub stars. I belive Haskell can reach a lot more than
       | it's currently doing if we get things easy to use.
       | 
       | If you want to build a web app with Haskell and play with type
       | classes check it out: https://ihp.digitallyinduced.com/ GitHub:
       | https://github.com/digitallyinduced/ihp
        
         | okkdev wrote:
         | I'm waiting for the new release because of the M1 fix that got
         | merged...
        
         | [deleted]
        
       | fn-mote wrote:
       | I'm not sure what this adds over LYaH. Possibly it is useful
       | because you have to survive until LYaH Chapter 8 for "Typeclasses
       | 102"? [1]
       | 
       | The basic post was fine I didn't see any lightbulb moments. It
       | works through an example showing how to add your own data type to
       | Eq and Ord.
       | 
       | The later post, "What's That Typeclass: Monoid" could have been
       | interesting. To me it went to mathematically-abstract. Like every
       | other Haskell post.
       | 
       | Example quote: "...because a semigroup is a monoid without an
       | identity element..." To be fair, they have defind SemiGroup, but
       | really -- who is the audience for this?
       | 
       | This is good for a laugh though:
       | 
       | > Why do you need monoids?
       | 
       | > In general, monoids are not very advanced, interesting, or
       | cool.
       | 
       | [1] http://learnyouahaskell.com/making-our-own-types-and-
       | typecla...
        
         | dmkolobov wrote:
         | Respectfully disagree about monoids! Plenty of cool stuff
         | there, here's one of my favorites, a diagramming library built
         | around monoids:
         | 
         | https://repository.upenn.edu/cgi/viewcontent.cgi?article=177...
        
         | mhitza wrote:
         | Monoids are pretty cool in theory, and at the same time, the
         | tool I use least of when working with Haskell.
         | 
         | This page [0] really shows how elegant Monoid comprehension
         | would be when implementing SQL-like operations within pure
         | Haskell code. (Goes over desugaring, implementation details and
         | comparison to list/monad comprehensions, just jump down to
         | examples)
         | 
         | [0]
         | https://lptk.github.io/programming/2018/10/04/comprehending-...
        
           | chas wrote:
           | Funny enough, monoids/semigroups are one of my favorite parts
           | of Haskell and I really miss having an explicit abstraction
           | for them in other languages.
           | 
           | A lot of the code I write is looping over all of the values
           | of a data structure to either look for a certain condition
           | being true (any/all boolean monoid), look for an extremal
           | value (min/max semigroup), or combine all of the values in
           | the data structure (sum/product/average monoid). The product
           | of a monoid is also a monoid, so if you want to do two or
           | more of those operations at once, the code remains simple and
           | orthogonal while only traversing the structure once.
           | 
           | In particular, all of the those operations are nicely
           | expressed as one-lines using foldMap (https://hackage.haskell
           | .org/package/base-4.9.1.0/docs/Data-F...). If you have a data
           | structure called `xs` and each element in data structure has
           | an integer field called `size` you can do the following by
           | using foldMap with different Monoid instances.
           | 
           | Sum the sizes:                 let (Sum total_size) = foldMap
           | (\x -> Sum (size x)) xs
           | 
           | Check if any size is greater than 5:                 let (Any
           | over_threshold) = foldMap (\x -> Any ((size x) > 5)) xs
           | 
           | Do both in one pass:                 let (Sum total_size, Any
           | over_threshold) = foldMap (\x -> (Sum (size x), Any ((size x)
           | > 5))) xs
           | 
           | Get the first entry with a size greater than 5:
           | let (First over_threshold) = foldMap (\x -> First (if (size
           | x) > 5 then Just x else Nothing)) xs
           | 
           | Get all entries with a size greater than 5:
           | let over_threshold = foldMap (\x -> if (size x) > 5 then [x]
           | else []) xs
           | 
           | Since all of these operations are associative, we can
           | completely change the data structure or run the operations in
           | parallel or concurrently and the code will still behave
           | exactly the same. These nice properties mean that when I'm
           | thinking about these sorts of tasks in any language, I think
           | about what monoid or semigroup captures a given operation,
           | rather than any of the mechanics of writing the loop. I find
           | clarifies my thinking a lot.
        
         | aroccoli wrote:
         | Thank you for the feedback!
         | 
         | To compare with Learn You a Haskell, I wanted to provide a
         | different option / way of grasping the concept with, hopefully,
         | examples that are relatable to some people more than LYAH.
         | Having a few different explanations of the same thing is not a
         | bad thing in my eyes since different things click with
         | different people.
         | 
         | Regarding Monoid article -- it is sad to hear that since my
         | goal was to provide something that would be unlike the
         | "mathematically-abstract" posts. It has plenty of examples and
         | a rather long exposition, and I am not sure how much more it is
         | possible to improve it without losing any meaning for the word
         | "monoid".
         | 
         | Semigroups and monoids is a rather awkward moment there, I
         | didn't manage to find a perfect way to cover that. But, to be
         | honest, I did mention what a monoid is plenty of times, and I
         | did mention what an identity element is several times as well.
         | So a careful reader should be able to imagine what a semigroup
         | is if necessary.
         | 
         | Anyway, thank you for reading the articles and pointing my
         | attention towards that. I will for sure look at that part
         | again. :)
         | 
         | -- Author
        
           | m1kal wrote:
           | I liked the text about typeclasses. It is a standalone piece,
           | "Typeclasses 102" in LYaH is a part of a chapter of a bigger
           | piece. I think you achieved your goal - your Pokemon example
           | is simple to grasp and shows how to derive type classes and
           | implement functions by hand:)
           | 
           | (not commenting about monoid/subgroup part)
        
       ___________________________________________________________________
       (page generated 2022-04-27 23:02 UTC)