Correcting the output type in HLists

I am trying to put together some code to compile. This meant taking HList

, extracting strings and concatenating them together.


{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Lib
    ( y
    ) where

import Data.HList

data HConcat2 = HConcat2
instance ApplyAB HConcat2 (String, String) String where
  applyAB _ (a,b) = a ++ b
instance ApplyAB HConcat2 (Int, String) String where
  applyAB _ (_,a) = a

x :: HList '[Int, String, Int, String]
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil

y :: String
y = hFoldr HConcat2 "Result: " x

      

Unfortunately when I try to compile this it gives me

    No instance for (ApplyAB HConcat2 ([Char], [Char]) r2)
      arising from a use of 'hFoldr'
    The type variable 'r2' is ambiguous
    Note: there is a potential instance available:
      instance ApplyAB HConcat2 (String, String) String
        - Defined at src / Web / Rusalka / Condition.hs: 274: 10
    In the expression: hFoldr HConcat2 "Result:" x
    In an equation for 'y': y = hFoldr HConcat2 "Result:" x

How do I convince him to use the instances I have declared?

+3


source to share


1 answer


There is no functional class dependency ApplyAB

, so when GHC tries to select an instance, the input types do not determine the type of the result. In this case, all intermediate types in the chain hFoldr

become ambiguous, and the GHC does not know which instances to choose.

To solve this problem, you can use a trick where you keep the result type completely generic in the instance head and use an equational constraint ~

to constrain it after GHC has selected the instance (only the instance head is used to select).

If you run :i ApplyAB

in GHCi, you will notice that some of the predefined instances use such equational constraints.



Using this (and appendix TypeFamilies

) your code works for me:

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

module Lib
    ( y
    ) where

import Data.HList

data HConcat2 = HConcat2
instance s ~ String => ApplyAB HConcat2 (String, String) s where
  applyAB _ (a,b) = a ++ b
instance s ~ String => ApplyAB HConcat2 (Int, String) s where
  applyAB _ (_,a) = a

x :: HList '[Int, String, Int, String]
x = 3 .*. "Hello" .*. 4 .*. " World" .*. HNil

y :: String
y = hFoldr HConcat2 "Result: " x

      

+2


source







All Articles