Skip to content

Instantly share code, notes, and snippets.

@chrisdone
Last active January 2, 2019 10:02
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chrisdone/93e72fd09aa82b83cd53793f6823017f to your computer and use it in GitHub Desktop.
Save chrisdone/93e72fd09aa82b83cd53793f6823017f to your computer and use it in GitHub Desktop.
Using type-level lits, overloaded strings, and splices to make named tuples
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
-- | This module provides a way to name the fields in a regular
-- Haskell tuple and then look them up later, statically.
module NamedTuple
(module NamedTuple
,module Data.Proxy)
where
import Data.String
import Language.Haskell.TH
import Data.Proxy
import GHC.TypeLits
-- | The syntax and the type of a field assignment.
data l := t = KnownSymbol l => Proxy (l :: Symbol) := t
-- Simple show instance for a field.
instance Show t => Show (l := t) where
show (l := t) = symbolVal l ++ " := " ++ show t
-- | Means to search for a field within a tuple.
-- We could add `set` to this, or just have a `lens` method
-- which generates a lens for that field.
class Has (l :: Symbol) r a | l r -> a where
get :: f l -> r -> a
-- Instances which we could easily generate with TH.
instance Has l ((l := a), u0) a where get _ ((_ := a),_) = a
instance Has l (u0, (l := a)) a where get _ (_,(_ := a)) = a
instance Has l ((l := a), u0, u1) a where get _ ((_ := a),_,_) = a
instance Has l (u0, (l := a), u1) a where get _ (_,(_ := a),_) = a
instance Has l (u0, u1, (l := a)) a where get _ (_,_,(_ := a)) = a
-- Provide convenient syntax: $("foo") for Proxy :: Proxy "foo".
instance IsString (Q Exp) where
fromString str = [|Proxy :: Proxy $(litT (return (StrTyLit str)))|]
{-# LANGUAGE DataKinds, OverloadedStrings, TemplateHaskell #-}
-- Taken from JSON from the GitHub API.
import NamedTuple
mentioned =
(
$("url") := "https://api.github.com/repos/commercialhaskell/intero/issues/64",
$("title") := "Support GHCJS",
$("user") := (
$("login") := "themoritz",
$("id") := 3522732
)
)
> mentioned
(url := "https://api.github.com/repos/commercialhaskell/intero/issues/64",title := "Support GHCJS",user := (login := "themoritz",id := 3522732))
> get $("login") (get $("user") mentioned)
"themoritz"
> get $("id") (get $("user") mentioned)
3522732
> :t get $("id") (get $("user") ($("url") := "https://api.github.com/repos/commercialhaskell/intero/issues/64", $("title") := "Support GHCJS", $("user") := ($("login") := "themoritz", $("id") := 3522732)))
Num a => a
> get $("id") (get $("user") ($("url") := "https://api.github.com/repos/commercialhaskell/intero/issues/64", $("title") := "Support GHCJS", $("user") := ($("login") := "themoritz", $("id") := 3522732)))
3522732
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment