Let us rethink the deeply embedded \gls{DSL} design.
Remember that in shallow embedding, the semantics are embedded in the language construct functions.
Obtaining extensibility both in constructs and semantics was accomplished by abstracting the semantics functions to type classes, making the constructs overloaded in the semantics.
Let us rethink the deeply embedded \gls{DSL} design.
Remember that in shallow embedding, the semantics are embedded in the language construct functions.
Obtaining extensibility both in constructs and semantics was accomplished by abstracting the semantics functions to type classes, making the constructs overloaded in the semantics.
Little boilerplate denotes the amount of scaffolding and boilerplate required.
For example, hybrid embedding requires a transcoding step between the deep syntax and the shallow core language.
Little boilerplate denotes the amount of scaffolding and boilerplate required.
For example, hybrid embedding requires a transcoding step between the deep syntax and the shallow core language.
\begin{threeparttable}[b]
\small
\caption{Comparison of embedding techniques, extended from \citet[\citesection{3.6}]{sun_compositional_2022}.}%
\begin{threeparttable}[b]
\small
\caption{Comparison of embedding techniques, extended from \citet[\citesection{3.6}]{sun_compositional_2022}.}%
This means that when \haskelllhstexinline{Cons} is pattern matched, the overloading of the type class constraint for \haskelllhstexinline{c dt} can be solved by the compiler.
\GHCmod{KindSignatures} is used to force the kinds of the type parameters and the kind of \haskelllhstexinline{dt} is polymorphic (\GHCmod{PolyKinds}) so that the \haskelllhstexinline{Record} data type can be used for \glspl{DSL} using type classes but also type constructor classes (e.g.\ when using \glspl{GADT}).
This means that when \haskelllhstexinline{Cons} is pattern matched, the overloading of the type class constraint for \haskelllhstexinline{c dt} can be solved by the compiler.
\GHCmod{KindSignatures} is used to force the kinds of the type parameters and the kind of \haskelllhstexinline{dt} is polymorphic (\GHCmod{PolyKinds}) so that the \haskelllhstexinline{Record} data type can be used for \glspl{DSL} using type classes but also type constructor classes (e.g.\ when using \glspl{GADT}).
data Record (dt :: k) (clist :: [k -> Constraint]) where
Nil :: Record dt '[]
Cons :: c dt => Record dt cs -> Record dt (c ': cs)
data Record (dt :: k) (clist :: [k -> Constraint]) where
Nil :: Record dt '[]
Cons :: c dt => Record dt cs -> Record dt (c ': cs)
To incorporate this type in the \haskelllhstexinline{Expr} type, the \haskelllhstexinline{Ext} constructor changes from containing a single witness dictionary to a \haskelllhstexinline{Record} type containing all the required dictionaries.
To incorporate this type in the \haskelllhstexinline{Expr} type, the \haskelllhstexinline{Ext} constructor changes from containing a single witness dictionary to a \haskelllhstexinline{Record} type containing all the required dictionaries.
Furthermore, we define a type class (\haskelllhstexinline{In}) that allows us to extract explicit dictionaries \haskelllhstexinline{Dict} from these records if the constraint can is present in the list.
Since the constraints become available as soon as the \haskelllhstexinline{Cons} constructor is matched, the implementation is a type-level list traversal.
Furthermore, we define a type class (\haskelllhstexinline{In}) that allows us to extract explicit dictionaries \haskelllhstexinline{Dict} from these records if the constraint can is present in the list.
Since the constraints become available as soon as the \haskelllhstexinline{Cons} constructor is matched, the implementation is a type-level list traversal.
This type class creates a record structure cons by cons if and only if all type class constraints are available in the list of constraints.
It is not required to provide instances for this for specific records or type classes, the two instances describe all the required constraints.
This type class creates a record structure cons by cons if and only if all type class constraints are available in the list of constraints.
It is not required to provide instances for this for specific records or type classes, the two instances describe all the required constraints.
class CreateRecord dt c where
createRecord :: Record dt c
instance CreateRecord d '[] where
class CreateRecord dt c where
createRecord :: Record dt c
instance CreateRecord d '[] where
Finally, using the \GHCmod{TypeFamilies} extension, type families can be created for bundling \haskelllhstexinline{`In`} constraints (\haskelllhstexinline{UsingExt}) and \haskelllhstexinline{CreateRecord} constraints \mbox{(\haskelllhstexinline{DependsOn})}, making the syntax even more descriptive.
E.g.\ \mbox{\haskelllhstexinline{UsingExt '[A, B, C] c}} expands to\newline\haskelllhstexinline{(CreateRecord (A c) c, CreateRecord (B c) c, CreateRecord (C c) c)}.
Finally, using the \GHCmod{TypeFamilies} extension, type families can be created for bundling \haskelllhstexinline{`In`} constraints (\haskelllhstexinline{UsingExt}) and \haskelllhstexinline{CreateRecord} constraints \mbox{(\haskelllhstexinline{DependsOn})}, making the syntax even more descriptive.
E.g.\ \mbox{\haskelllhstexinline{UsingExt '[A, B, C] c}} expands to\newline\haskelllhstexinline{(CreateRecord (A c) c, CreateRecord (B c) c, CreateRecord (C c) c)}.
-Similarly, \haskelllhstexinline{DependsOn '[A, B, C] s} expands to \haskelllhstexinline{(A `In` s, B `In` s, C `In` s)}.
+\hspace{-1.42284pt} Similarly, \haskelllhstexinline{DependsOn '[A, B, C] s} expands to \haskelllhstexinline{(A `In` s, B `In` s, C `In` s)}.
sub_g :: (Typeable d, GDict (d (Sub_g d)), Eq a, Num a) =>
Expr_g d a -> Expr_g d a -> Expr_g d a
sub_g e1 e2 = Ext_g gdict (Sub_g e1 e2)
sub_g :: (Typeable d, GDict (d (Sub_g d)), Eq a, Num a) =>
Expr_g d a -> Expr_g d a -> Expr_g d a
sub_g e1 e2 = Ext_g gdict (Sub_g e1 e2)
instance Print_g v => GDict (PrintDict_g v) where
gdict = PrintDict_g print_g
instance Opt_g v => GDict (OptDict_g v) where
gdict = OptDict_g opt_g
\end{lstHaskellLhstex}
instance Print_g v => GDict (PrintDict_g v) where
gdict = PrintDict_g print_g
instance Opt_g v => GDict (OptDict_g v) where
gdict = OptDict_g opt_g
\end{lstHaskellLhstex}
instance HasPrint_g d => Print_g (Expr_g d) where
print_g (Lit_g v) = show v
print_g (Add_g e1 e2) = "(" ++ print_g e1 ++ "+" ++ print_g e2 ++ ")"
instance HasPrint_g d => Print_g (Expr_g d) where
print_g (Lit_g v) = show v
print_g (Add_g e1 e2) = "(" ++ print_g e1 ++ "+" ++ print_g e2 ++ ")"
instance HasOpt_g d => Opt_g (Expr_g d) where
opt_g (Lit_g v) = Lit_g v
opt_g (Add_g e1 e2) = case (opt_g e1, opt_g e2) of
instance HasOpt_g d => Opt_g (Expr_g d) where
opt_g (Lit_g v) = Lit_g v
opt_g (Add_g e1 e2) = case (opt_g e1, opt_g e2) of