Search code examples
haskellgadt

How can I avoid multiple function implementations with GADTs?


First of all, here is a minimum example of my code:

{-# LANGUAGE GADTs #-}

-- package "url"
import Network.URL (exportURL, URL(..), URLType(..))

data MyURL a where
    GalleryURL :: URL -> MyURL URL
    PictureURL :: URL -> MyURL URL

url = URL { url_type = PathRelative, 
            url_path = "www.google.com", 
            url_params = []}

galleryURL = GalleryURL url

myExportURL :: MyURL a -> String
myExportURL (GalleryURL a) = exportURL a
myExportURL (PictureURL a) = exportURL a

main = print $ myExportURL galleryURL

I use GADTs to avoid mixing different kinds of URLs. The myExportURL function is the same for all kinds of URLs. Is there a way to use something like this:

myExportURL (_ a) = exportURL a

instead of repeating it for every subtype (what is the correct term?) of the GADT?

Any other comments on the code or the problem i am trying to solve are also welcome.


Solution

  • The correct term is "for every constructor".

    Your GADT look suspicious as all your constructors construct the same MyURL URL type. If it's all you want then you don't need GADTs in the first place and can use plain ADTs:

    data MyURL = GalleryURL URL | PictureURL URL
    

    To have shorter myExportUrl there are different options. One is to refactor the type:

    data URLKind = GalleryURL | PictureURL
    data MyURL = MyURL { myUrlKind :: URLKind, myExportURL :: URL }
    

    This way you can still use "short" form of construction, e.g. MyURL PictureURL foo. And also you can use myExportURL function generated for you by Haskell.

    GADTs are only necessary in advanced cases so if your example does not demonstrate fully why you need GADTs then let us now.