List of showables: OOP beats Haskell?

后端 未结 8 1288
无人及你
无人及你 2020-12-24 06:46

I want to build a list of different things which have one property in common, namely, they could be turned into string. The object-oriented approach is straightforward: defi

8条回答
  •  悲哀的现实
    2020-12-24 07:08

    If you really, really want, you can use a heterogeneous list. This approach really isn't useful for Show, because it has a single method and all you can do is apply it, but if your class has multiple methods this could be useful.

    {-# LANGUAGE PolyKinds, KindSignatures, GADTs, TypeFamilies
       , TypeOperators, DataKinds, ConstraintKinds, RankNTypes, PatternSynonyms  #-} 
    
    import Data.List (intercalate)
    import GHC.Prim (Constraint)
    
    infixr 5 :&
    data HList xs where 
      None :: HList '[] 
      (:&) :: a -> HList bs -> HList (a ': bs) 
    
    -- | Constraint All c xs holds if c holds for all x in xs
    type family All (c :: k -> Constraint) xs :: Constraint where 
      All c '[] = () 
      All c (x ': xs) = (c x, All c xs) 
    
    -- | The list whose element types are unknown, but known to satisfy
    --   a class predicate. 
    data CList c where CL :: All c xs => HList xs -> CList c  
    
    cons :: c a => a -> CList c -> CList c
    cons a (CL xs) = CL (a :& xs) 
    
    empty :: CList c 
    empty = CL None 
    
    uncons :: (forall a . c a => a -> CList c -> r) -> r -> CList c -> r 
    uncons _ n (CL None) = n 
    uncons c n (CL (x :& xs)) = c x (CL xs) 
    
    foldrC :: (forall a . c a => a -> r -> r) -> r -> CList c -> r 
    foldrC f z = go where go = uncons (\x -> f x . go) z 
    
    showAll :: CList Show -> String 
    showAll l = "[" ++ intercalate "," (foldrC (\x xs -> show x : xs) [] l) ++ "]" 
    
    test = putStrLn $ showAll $ CL $ 
      1 :& 
      'a' :& 
      "foo" :& 
      [2.3, 2.5 .. 3] :& 
      None 
    

提交回复
热议问题