How to put constraints on the associated data?

后端 未结 3 1317
温柔的废话
温柔的废话 2021-02-19 06:43

I would like to state that the associated data is always an instance of a certain class.

class (Context (Associated a b)) => Class a where
  data Associated a         


        
3条回答
  •  不要未来只要你来
    2021-02-19 07:10

    I don't have GHC 7.0.3 available, but I think this should work with it.

    You could pass the dictionaries around manually like this (using Context = Show as an example):

    {-# LANGUAGE ScopedTypeVariables, TypeFamilies, ExistentialQuantification #-}
    
    data ShowDict a = Show a => ShowDict
    
    class Class a where
      data Associated a :: * -> *
    
      getShow :: ShowDict (Associated a b)
    
    -- Convenience function
    getShowFor :: Class a => Associated a b -> ShowDict (Associated a b)
    getShowFor _ = getShow
    
    showAssociated :: Class a => Associated a b -> String
    showAssociated a = 
      case getShowFor a of
        ShowDict -> -- Show (Associated a b) is made available by this pattern match 
          show a
    
    instance Class Int where
      data Associated Int b = Foo deriving Show
    
      getShow = ShowDict
    
    main = print $ showAssociated Foo
    

    This is somewhat similar to the function copying you propose, but advantages are:

    • Avoids repetition (of `Context`'s method signatures)
    • Having `Show Baz` in context is somewhat more powerful than just having a function for showing a `Baz`, since it allows you to call (library) functions which require `Show Baz`, or use implied instances like `Show [Baz]`:
    showAssociateds :: forall a b. Class a => [Associated a b] -> String
    showAssociateds as = 
      case getShow :: ShowDict (Associated a b) of
        ShowDict ->
          show as
    

    The main disadvantage is that using getShow always requires an explicit type signature (functions like getShowFor can mitigate this).

提交回复
热议问题