How do I get the data type information from the type after converting the SOP representation?

I am trying to do fine print on datatype names, but I'm not sure how to do it with Generics-SOP.

In cases where I have a list of my new type, I can print out what I need quite easily:

class GTypeName f where
  gtypeName :: g f -> String

instance (HasDatatypeInfo a) => GTypeName (SOP I ('[ '[], '[a, [a]] ])) where
  gtypeName _ = "(Array " ++ name ++ ")"
    where
      name = datatypeName $ datatypeInfo (Proxy @ a)

      

As you can see, I am mapping to the List view and using the internal a

Datatype Info to get the name. But I don't know how to handle the case where I want to get the actual name of the top-level constructor itself.

In G6C Generics, I did the following:

instance (GTypeName f) => GTypeName (D1 m f) where -- peer inside
  gtypeName _ = gtypeName (Proxy @ f)

-- go into the Cons constructed type
instance {-# OVERLAPPING #-} (GTypeName f) => GTypeName (C1 ('MetaCons ":" g s) f) where
  gtypeName _ = gtypeName (Proxy @ f)

-- return the constructor name here
instance (KnownSymbol n) => GTypeName (C1 ('MetaCons n g s) f) where
  gtypeName _ = symbolVal (Proxy @ n)

-- take the left side, as this is the result of a type product from Cons
instance (GTypeName a) => GTypeName (a :*: b) where
  gtypeName _ =
    gtypeName (Proxy @ a)

-- match on array and take it out here
instance (GTypeName b) => GTypeName ((C1 ('MetaCons "[]" g s) f) :+: b) where
  gtypeName _ = "(Array " ++ gtypeName (Proxy @ b) ++ ")"

      

This is ultimately used with newtype and some data types:

newtype Status = Status Text

newtype OpenRequest = OpenRequest
  { path :: Path
  }

data Route req res = Route
  { method :: Method
  , url :: Url
  }

open :: Route OpenRequest Success
open = Route {method = POST, url = Url "/api/open"}

      

+3


source to share


1 answer


You can get the name of the top level constructor of a value using generics-sop like this:

constructor ::
  forall a .
  (Generic a, HasDatatypeInfo a) => a -> String
constructor a =
  hcollapse $
  hzipWith
    (\ con _args -> K (constructorName con))
    (constructorInfo (datatypeInfo (Proxy @a)))
    (unSOP $ from a)

      

Here constructorInfo ...

gives you a product containing all the constructor names of the corresponding data type. the call hzipWith

then selects the constructor that owns the given value a

.



Examples:

GHCi> constructor True
"True"
GHCi> constructor (Just 3)
"Just"
GHCi> constructor [1,2,3]
":"

      

Unfortunately, I'm not really clear on what you want to do with the list types, so I can't show you how to combine this with the code you already have.

+1


source







All Articles