Hacker News new | ask | show | jobs
by Iceland_jack 1477 days ago
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 :Ð
1 comments

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.