简体   繁体   中英

How do you reify/walk a record definition in Haskell

Given an record (not an instance of the record, the record definition itself) such as:

data Request
    = Expand { shortUrl :: [String]
             , hash     :: [String]
             }
    | Shorten { longUrl :: String
              , domain  :: String
              }
    | LinkEdit { link     :: String
               , title    :: Maybe String
               , note     :: Maybe String
               , private  :: Maybe Bool
               , user_ts  :: Maybe Int
               , archived :: Maybe Bool
               , edit     :: [String]
               }

how does one generate code using info from the record definition -- eg,:

mkReqUrl :: Request -> String
mkReqUrl (Expand shortUrl hash)   = mru "expand"  (zr "shortUrl"  [shortUrl] ++ zr "hash"   [hash])
mkReqUrl (Shorten longUrl domain) = mru "shorten" (zr "longUrl"   [longUrl]  ++ zr "domain" [domain])
...

I imagine some usage of TemplateHaskell and a generics library (eg, Uniplate) might do the trick. (I have peaked at the Lens implementation since it deals with record definitions, but I get lost in the code.).

GHC.Generics (actually, the docs for the version that will ship with GHC 7.8 are probably a better read; see below) is probably the way to do this now. First derive a Generic instance for your type:

{-# LANGUAGE DeriveGeneric #-}
data Request =  ...
     deriving Generic

You can then use from to convert your value to its generic representation type, and apply selName to the appropriate part of that structure (one of the S1 Blah_blah Foo... bits).

I'll leave that last part as an exercise for you; the structure of the Rep types are super byzantine. Although it looks like it will be well-documented in the new GHC here .

How to reify using Template Haskell

(the following has been hand-edited to make it easier to read)

> ghci -XTemplateHaskell
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
...
Prelude> :m + Language.Haskell.TH
Prelude Language.Haskell.TH> :{
data Request
  = Expand { shortUrl :: [String]
           , hash     :: [String]
           }
  | Shorten { longUrl :: String
            , domain  :: String
            }
  | LinkEdit { link     :: String
             , title    :: Maybe String
             , note     :: Maybe String
             , private  :: Maybe Bool
             , user_ts  :: Maybe Int
             , archived :: Maybe Bool
             , edit     :: [String]
             }
Prelude Language.Haskell.TH| :}
Prelude Language.Haskell.TH> $(stringE . show =<< reify ''Request)
...
"TyConI (DataD [] :Interactive.Request []
         [RecC :Interactive.Expand   [(:Interactive.shortUrl,NotStrict,AppT ListT (ConT GHC.Base.String))
                                     ,(:Interactive.hash,NotStrict,AppT ListT (ConT GHC.Base.String))]
         ,RecC :Interactive.Shorten  [(:Interactive.longUrl,NotStrict,ConT GHC.Base.String)
                                     ,(:Interactive.domain,NotStrict,ConT GHC.Base.String)]
         ,RecC :Interactive.LinkEdit [(:Interactive.link,NotStrict,ConT GHC.Base.String)
                                     ,(:Interactive.title,NotStrict,AppT (ConT Data.Maybe.Maybe) (ConT GHC.Base.String))
                                     ,(:Interactive.note,NotStrict,AppT (ConT Data.Maybe.Maybe) (ConT GHC.Base.String))
                                     ,(:Interactive.private,NotStrict,AppT (ConT Data.Maybe.Maybe) (ConT GHC.Types.Bool))
                                     ,(:Interactive.user_ts,NotStrict,AppT (ConT Data.Maybe.Maybe) (ConT GHC.Types.Int))
                                     ,(:Interactive.archived,NotStrict,AppT (ConT Data.Maybe.Maybe) (ConT GHC.Types.Bool))
                                     ,(:Interactive.edit,NotStrict,AppT ListT (ConT GHC.Base.String))]]
         [])"

One can then walk the structure returned from reify using standard recursion/pattern matching.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM