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