codesnippets:parametrictypeforanintermediatevaluewhencombiningfunctions

Parametric type for an intermediate value when combining functions

  • example with the folling problem(s):
    • function buildNRender has an ambigious intermediate parametric type
    • the type of buildNRender has no parametric type g involved at all
      • hence, it does not make sense to have buildNRender as a member of class Builder
    • code
      module Main where
       
      import qualified Data.Word as W
      import qualified Octetable as Oct
       
      main :: IO ()
      main = 
          do
              print (buildNRender "123")
       
      data MyData = MyData Integer
       
      data Construction model = Contains model | Error String
          deriving Show
       
      class Builder g where
          build :: String -> (Construction g)
          render :: (Construction g) -> [W.Word8]
          buildNRender :: String -> [W.Word8]
          buildNRender = render . build
       
      instance Builder MyData where
          build s = Contains (MyData (read s :: Integer))
          render (Contains (MyData n)) = Oct.toOctets n
          render (Error _) = []
    • compiles, with error:
      app\Main.hs:19:5: error:
          * Could not deduce (Builder g0)
            from the context: Builder g
              bound by the type signature for:
                         buildNRender :: forall g. Builder g => String -> [W.Word8]
              at app\Main.hs:19:5-39
            The type variable `g0' is ambiguous
          * In the ambiguity check for `buildNRender'
            To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
            When checking the class method:
              buildNRender :: forall g. Builder g => String -> [W.Word8]
            In the class declaration for `Builder'
         |
      19 |     buildNRender :: String -> [W.Word8]
         |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  • example that solves the problem with extensions
    • code
      {-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}
       
      module Main where
       
      import qualified Data.Word as W
      import qualified Octetable as Oct
       
      main :: IO ()
      main = 
          do
              print (buildNRender @MyData "123")
       
      data MyData = MyData Integer
       
      data Construction model = Contains model | Error String
          deriving Show
       
      class Builder g where
          build :: String -> (Construction g)
          render :: (Construction g) -> [W.Word8]
       
      buildNRender :: forall g . Builder g => String -> [W.Word8]
      -- forall g . introduces the Scope of Type Variable g
      -- needs extension AllowAmbiguousTypes
      buildNRender = render . build @g -- @g is a Type Application
       
      instance Builder MyData where
          build s = Contains (MyData (read s :: Integer))
          render (Contains (MyData n)) = Oct.toOctets n
          render (Error _) = []
  • example that solves the problem with proxy passing
    • NOTE: Proxy has a type parameter that is not used and does not even carry data.
    • code
      module Main where
       
      import qualified Data.Word as W
      import qualified Octetable as Oct
       
      main :: IO ()
      main = 
          do
              print (buildNRender (Proxy :: Proxy MyData) "123")
       
      data MyData = MyData Integer
       
      data Construction model = Contains model | Error String
          deriving Show
       
      class Builder g where
          build :: String -> (Construction g)
          render :: (Construction g) -> [W.Word8]
          buildNRender :: proxy g -> String -> [W.Word8]
          buildNRender p = render . applyProxy p build
              where
                  applyProxy :: proxy g -> f (c g) -> f (c g)
                  applyProxy _ = id
       
      instance Builder MyData where
          build s = Contains (MyData (read s :: Integer))
          render (Contains (MyData n)) = Oct.toOctets n
          render (Error _) = []
       
      data Proxy a = Proxy
  • example that solves the problem with Tagged
    • NOTE: Proxy has a type parameter that is not used and does not even carry data.
    • code
      module Main where
       
      import qualified Data.Word as W
      import qualified Octetable as Oct
      import qualified Data.Tagged as Tg
       
      main :: IO ()
      main = 
          do
              print ((getTaggedFunc (buildNRender :: Tg.Tagged MyData (String -> [W.Word8]))) "123")
       
      getTaggedFunc :: Tg.Tagged g (String -> [W.Word8]) -> (String -> [W.Word8])
      getTaggedFunc (Tg.Tagged f) = f
       
      data MyData = MyData Integer
       
      data Construction model = Contains model | Error String
          deriving Show
       
      class Builder g where
          build :: String -> (Construction g)
          render :: (Construction g) -> [W.Word8]
          buildNRender :: Tg.Tagged g (String -> [W.Word8])
          buildNRender = (render .) <$> applyTag build
              where
                  applyTag :: f (c g) -> Tg.Tagged g (f (c g))
                  applyTag = Tg.Tagged
       
      instance Builder MyData where
          build s = Contains (MyData (read s :: Integer))
          render (Contains (MyData n)) = Oct.toOctets n
          render (Error _) = []

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
You could leave a comment if you were logged in.
codesnippets/parametrictypeforanintermediatevaluewhencombiningfunctions.txt · Last modified: by 127.0.0.1

Except where otherwise noted, content on this wiki is licensed under the following license: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki