Hacker News new | past | comments | ask | show | jobs | submit login
Learn Haskell by building a blog generator – a project-oriented Haskell book (lhbg-book.link)
230 points by gilmi on June 8, 2022 | hide | past | favorite | 40 comments



That's the perfect learning project because there's something tangible at the end.

Whenever the question of "How do I learn Haskell" comes up, I always suggest to come up with a project that would be useful on its own, regardless of the technology used to create it, and use Haskell to do it. In my case it was a pandoc filter to embed plots in documents (https://github.com/LaurentRDC/pandoc-plot), which was ultimately useful to create my PhD dissertation.

There's only so much you can learn about Haskell by working through toy examples.


Great project; I'd have loved to have had it when I was writing my dissertation - hell, I'd have liked anything that would have let me write it in vim and just generate the final submission per the university's format, because I hate Word.


If you want to do web development with Haskell beyond building a blog generator, a good starting point is IHP (https://ihp.digitallyinduced.com/ https://github.com/digitallyinduced/ihp). IHP is Haskell's version of Laravel/Rails/Django. It's really a superpower to have Haskell's type system combined with the rapid development approach of Rails :) (Disclaimer: I'm founder of the company that makes IHP)


I think IHP for learning Haskell has the same flaw that Rails always did. You have no idea what is part of the language and what is part of the framework. You'll get stuck once you stray from the golden path.

I'd recommend starting with Scotty instead. It's much easier to understand what it is doing. Use Lucid for HTML rendering, and your choice of DB libraries (I like Selda). These all avoid template haskell and don't rename any prelude functions. If you add them one at a time you'll see what each one is offering and understand where to go when you need to do something more complicated


I was tempted to try it, but then I saw that some core features (like mysql) are for paid versions only so its a big red flag already


Mysql support is not implemented at the moment. If there's someone paying for the development we could have it. You're of course also free to contribute it yourself to the open source version, then it wouldn't need to be part of the commercial version.

Some more background on why IHP has a paid variant can be found here: https://ihp.digitallyinduced.com/blog/6392ad84-e96a-46ce-9ab...


I don't get it. How can it be part of the commercial version if it is not implemented.


Not OP, but it sounds like MySQL support isn't out yet. So I think the business plan can help them get paid to implement it. No clue if that means the FOSS version would receive those upstream changes once it's done.


software needs work and devs have bills. its unfortunate but we don't have a government currently giving grants to open source devs yet.


I'm really not a fan of IHP for that purpose due to how it redefines so much of the Haskell Prelude without making it clear it does that.


Ah, I was wondering why you post about IHP on most Haskell threads here and I just noticed it is a commercial product. You should probably disclose that this is an advertisement if it is permitted at all.


IHP is mostly an open source project.

I comment on most Haskell threads about IHP because I would love to see more Haskell adoption. Most people think Haskell is about Monads and Math, with IHP we want to show that Haskell can be used in a very productive way to build things. The comments are typically well received, so I don't see any problem with this.


This is really cool! I've been looking for something like for a while - my learning path was through LYAH and Real-World Haskell (also tried Haskell from the first principles but a bit too extensive IMO). I think this would fit in perfectly between LYAH and RWH.

I am using Haskell mostly for writing compilers (https://github.com/wasp-lang/wasp currently), but I believe if the tutorial isn't using a lot of specialized libraries/frameworks (which seems to be the case from the first glance), a majority of the material taught should be transferable to any domain.


Thanks!


If you’re more inclined to visual and/or musical arts, I’d recommend “Th Haskell School Of Expression” by Paul Hudak. He guides you through the language and the techniques with an eye for concise, expressive code that has good runtime characteristics.


Kudos to the author. The best way to teach something is to start with a foundation of nothing and then step by step building layers of understanding on top of it. Most other Haskell tutorials fail to do this.


Thank you!


Oh this looks fun getStructureString and render can be defined as record selectors

  newtype Structure = Structure { getStructureString :: String }
  newtype Html      = Html      { render             :: String }
BlockArguments let you write expressions like myhtml

  myhtml :: Html
  myhtml =
    html_
      "My title"
      ( append_
        (h1_ "Heading")
        ( append_
          (p_ "Paragraph #1")
          (p_ "Paragraph #2")
        )
      )
in a more domain-specific style. De gustibus, but some may prefer it to the parentheses.

  {-# Language BlockArguments #-}

  myhtml :: Html
  myhtml =
    html_ "My title" do
      append_
        do h1_ "Heading"
        do append_
             do p_ "Paragraph #1"
             do p_ "Paragraph #2"
or using the associativity of append_ = (<>)

  myhtml =
    html_ "My title" do
      h1_ "Heading" <> p_ "Paragraph #1" <> p_ "Paragraph #2"

  myhtml =
    html_ "My title" do mconcat
      [ h1_ "Heading"
      , p_ "Paragraph #1"
      , p_ "Paragraph #2"
      ]
All examples of 'concat . map' can be replaced with.. concatMap :Ð


Instead of defining append_ for structure

  newtype Structure = Structure String

  append_ :: Structure -> Structure -> Structure
  append_ (Structure c1) (Structure c2) = Structure (c1 <> c2)

  empty_ :: Structure
  empty_ = Structure ""
the <> operator (from Semigroup) can be reused by deriving it via the underlying String type (edit: I see this is suggested later in the tutorial).

  {-# Language DerivingStrategies         #-}
  {-# Language GeneralizedNewtypeDeriving #-}

  newtype Structure = Structure String
    deriving
    newtype (Semigroup, Monoid)

  append_ :: Structure -> Structure -> Structure
  append_ = (<>)

  empty_ :: Structure
  empty_ = mempty
Semigroup and Monoid let us use a lot of standard vocabulary

  concatStructure :: [Structure] -> Structure
  concatStructure list =
    case list of
      [] -> empty_
      x : xs -> x <> concatStructure xs
becomes

  concatStructure :: [Structure] -> Structure
  concatStructure = mconcat
or

  concatStructure = fold
Also in the detour about kinds they are written as * while the ecosystem is moving towards a more uniform Type name.

  {-# Language StandaloneKindSignatures #-}

  import Data.Kind (Type)

  type Tuple :: Type -> Type -> Type
  data Tuple a b = Tuple a b

  type Either :: Type -> Type -> Type
  data Either a b = Left a | Right b


Right but the point of the book is to ease learners into the language (and teach core concepts), and not throw them into the deep end of it.

Also, I'll update the text about kinds when GHC will use Type instead of * everywhere:

$ ghci

GHCi, version 9.2.2: https://www.haskell.org/ghc/ :? for help

λ> :k (,)

(,) :: * -> * -> *


Not critiquing, I was giving a stream of consciousness while reading. I enjoyed it

Until we get Type by default the best we can do is enable NoStarIsType


Thank you. I'm glad you're enjoying it. Sorry if I sounded a bit aggressive here.

I think one of the cool things about Haskell is that there's quite a high ceiling in terms of solutions you can reach for. On many occasions when one get annoyed by something and thinks "there must be a better way", there is one.

You show how one with more knowledge and command of the language can make it do a lot of things for free, and that is very cool! But I can also see how these solutions can look a bit intimidating for people with less experience, and it's important to take this into account as well.

This is kind of a double edged sword. Gotta find the right balance.


I didn't take it as aggressive. I hope people who are curious get something out of my comment but without intimidating others, perhaps I write it as a bonus that people can ignore if it doesn't help but you are right that some people could be put off by it.


Sounds like a generally reasonable approach to me.


I'm using this for my 10th? shot at diving into Haskell. I'd certainly appreciate bonus material on emerging best standards that is just starred and put into an appendix.


On the "where to go next?" appendix there's a link to my Haskell study plan[0] which has links to a bunch of extra material.

[0]: https://github.com/soupi/haskell-study-plan


Perfect! Thanks!


I have found Hakyll to be useful in this space, if you want to move from building your own to configuring/extending your own.


At first sight I’ve read “an object-oriented Haskell book”.

[brief pause for contemplating the thought]

Naturally, someone went there: https://www.parsonsmatt.org/tutorials/


The linked articles are actually about how to translate problems from an OOP perspective into idiomatic Haskell.


How you would write tests in a real project?

I suppose it's not writing out the entire program and then writing the tests, as seems to be implied. That would mean a lot of manual testing.

Or is there a Haskell REPL where you can try out small pieces before saving them?


When you create a project description for your project (for the package manager) you can define a library, executables and test suites.

In the test suite you write your tests against the library. You can do that at any stage, even before writing a line of library code.

But yes, Haskell also has a REPL that can be used to experiment with code.


In addition to the other good answers you've gotten, I would like to point out that Haskell has QuickCheck (https://hackage.haskell.org/package/QuickCheck) which, if I'm not mistaken, more or less pioneered property testing. Property testing libraries are available in many languages now but they never seem to be as capture the magic of QuickCheck. (There's also https://hackage.haskell.org/package/hedgehog which is sort of a "modern alternative" to QuickCheck but I still prefer the OG).


You have testing libraries in Haskell just like in every other languages. For example: https://hackage.haskell.org/package/tasty


Yes, there is GHCi, the Haskell interpreter and repl comes bundled with the compiler.

You can load your entire project in the repl and try your functions there.



For anyone that does decide to learn Haskell, you can easily get a job afterwards working on the Cardano blockchain. Smart contract devs are in high demand, and Cardano uses a variant of Haskell that is relatively unique to the space.


I've been following for at least a year and find that the jobs pay is very low in comparison to Rust; or Solidity.

I also don't see much jobs available.

Where do you see those job listings?


Is the website/book/blog self-hosting?

https://en.wikipedia.org/wiki/Self-hosting_(compilers)


No. It is built with mdbook[0].

[0]: https://rust-lang.github.io/mdBook




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: