Untitled

mail@pastecode.io avatar
unknown
haskell
2 years ago
1.7 kB
32
No Index
Never
    {-# LANGUAGE DataKinds #-}

    import Control.Newtype (Newtype)
    import qualified Control.Newtype as Newtype
    import Witch (from)

    -- | A bank account ID for an account of some @accountKind@.
    newtype AccountID accountKind = AccountID Text
    instance Newtype (AccountID accountKind) Text

    -- | Bank account info for an account of some @accountKind@.
    newtype AccountInfo accountKind = AccountInfo Text
    instance Newtype (AccountInfo accountKind) Text

    -- | The different kinds of bank accounts.
    data AccountKind = A | B | C deriving Show

    -- | Demote the kind of bank account to the value level.
    class OfAccountKind (t :: AccountKind) where
      demoteAccountKind :: f t -> AccountKind

    -- Possible to derive these instances? Preferably without TH?
    instance OfAccountKind 'A where demoteAccountKind _ = A
    instance OfAccountKind 'B where demoteAccountKind _ = B
    instance OfAccountKind 'C where demoteAccountKind _ = C

    changeType :: (Newtype a inner, Newtype b inner) => a -> b
    changeType = Newtype.pack . Newtype.unpack

    -- | @AccountInfo@ for a bank account of some kind, looked up by @AccountID@.
    accountInfo
    :: OfAccountKind accountKind
    => AccountID accountKind
    -> Either Text (Maybe (AccountInfo accountKind))
    accountInfo accountID =
      fmap (fmap changeType) $ case demoteAccountKind accountID of
        A -> Right $ accountAInfo $ changeType accountID
        x -> Left $ from $ "Unsupported AccountKind " <> show x

    -- | @AccountInfo@ for a bank account of kind @A@.
    accountAInfo :: AccountID 'A -> Maybe (AccountInfo 'A)
    accountAInfo _accountID =
      pure $ AccountInfo "Info found via lookup of '_accountID'"