Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enforcing tag uniqueness #33

Open
joeyh opened this issue Jun 28, 2017 · 3 comments
Open

enforcing tag uniqueness #33

joeyh opened this issue Jun 28, 2017 · 3 comments

Comments

@joeyh
Copy link

joeyh commented Jun 28, 2017

"Each tag must be unique within a given message, though this is not currently checked or enforced."

I really like this library, but keeping the tags unique has felt like walking on eggshells when using it. Perhaps there could be some way to enforce tag uniqueness?

@NathanHowell
Copy link
Member

Certainly would be a desirable addition. I think it can be done with Sort and a variation of Nub from either https://hackage.haskell.org/package/singletons-2.2 (in Data.Singletons.Prelude.List) or the slightly lighter https://hackage.haskell.org/package/type-level-sets. Always happy to take pull requests :-)

@joeyh
Copy link
Author

joeyh commented Jun 28, 2017 via email

@NathanHowell
Copy link
Member

It does, sort of. The structure of the message can be traversed and field tags extracted at compile time, here's the basic idea:

{-# language DataKinds #-}
{-# language KindSignatures #-}
{-# language PolyKinds #-}
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# language UndecidableInstances #-}

import GHC.Generics
import GHC.TypeLits

data Field (n :: Nat) a

type family Concat (x :: [k]) (y :: [k]) :: [k] where
  Concat (x ': xs) ys = x ': Concat xs ys
  Concat '[] ys = ys

type family FieldTags (f :: * -> *) :: [Nat] where
  FieldTags (M1 i c a) = FieldTags a
  FieldTags (a :*: b) = Concat (FieldTags a) (FieldTags b)
  FieldTags (a :+: b) = Concat (FieldTags a) (FieldTags b)
  FieldTags (K1 i (Field n a)) = '[n]

Applying FieldTags to the generic representation of the message will return a type level list containing the tags. Then it's just a matter of sorting them and checking for duplicates.

Ok, modules loaded: Main.
*Main> :kind! FieldTags (Rep (Field 1 Int, Field 3 Double))
FieldTags (Rep (Field 1 Int, Field 3 Double)) :: [Nat]
= '[1, 3]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants