ginger icon indicating copy to clipboard operation
ginger copied to clipboard

Need help with (untyped ?) / heterogeneous dictionary as context to template

Open plsnp opened this issue 5 years ago • 0 comments

Hello

From https://github.com/tdammers/ginger/blob/master/doc/getting-started.markdown#running---the-easy-interface

Note that, because Ginger is a dynamically typed language (or, actually, an untyped language), passing values to a template execution context requires conversion to Ginger values, represented on the Haskell side as the GVal type. The ToGVal typeclass exposes a number of convenience functions that can be used for this purpose, and there are instances for many of Haskell's standard data types.

I wanted to model a dictionary with different types of values. When i adapt the easyRender example in the manual it gets really complicated (for me personally it was anyway).

Here is the changed code with the type errors it yields: >>> CODE <<<

context :: HashMap Text (GVal (Run SourcePos (Writer Text) Text))
context = HashMap.fromList
    [ ("name", toGVal ("Alice" :: Text))
    , ("location", toGVal ("Wonderland" :: String))
    , ("age", toGVal (155 :: Int))
    ]

Maybe this could be the right type ?? It typechecked on this level but still throw another type error near easyRender

Proposed was the following patch:

-- This would work with the patch below
context :: HashMap Text (GVal m)
context = HashMap.fromList
    [ ("name", toGVal ("Alice" :: Text))
    , ("location", toGVal ("Wonderland" :: String))
    , ("age", toGVal (155 :: Int))
    ]

{-

--- ginger-0.10.1.0/src/Text/Ginger/GVal.hs     2001-09-09 03:46:40.000000000 +0200
+++ ginger-0.10.1.0-my/src/Text/Ginger/GVal.hs  2020-09-02 10:10:21.853396692 +0200
@@ -3,6 +3,7 @@
 {-#LANGUAGE FlexibleInstances #-}
 {-#LANGUAGE ScopedTypeVariables #-}
 {-#LANGUAGE RankNTypes #-}
+{-#LANGUAGE TypeFamilies #-}
 
 -- | GVal is a generic unitype value, representing the kind of values that
 -- Ginger can understand.
@@ -314,7 +315,7 @@
     toGVal :: a -> GVal m
 
 -- | Trivial instance for 'GVal' itself.
-instance ToGVal m (GVal m) where
+instance (m ~ m') => ToGVal m (GVal m') where
     toGVal = id
 
 instance ToGVal m () where

-}

Supposingly the code could then look like this

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}

-- ...

newtype GVal' m = GVal' { unGVal' :: GVal m }

toGVal' v = GVal' (toGVal v)

instance (m ~ m') => ToGVal m (GVal' m') where
    toGVal = unGVal'

context :: HashMap Text (GVal' m)
context = HashMap.fromList
    [ ("name", toGVal' ("Alice" :: Text))
    , ("location", toGVal' ("Wonderland" :: String))
    , ("age", toGVal' (155 :: Int))
    ]

I didn't look if this patch makes sense but it seemed a very helpful suggestion.

For me the documentation is not clear about how to handle this scenario. I think it's quite common to have a dictionary with different types. Think of person with age int and name string. Maybe also something in ginger can be changed to simplify types or instances, i don't know.

Other than this it looks like a really nice package, i'm eager to get my first template working :)

plsnp avatar Sep 02 '20 09:09 plsnp