Untitled

mail@pastecode.io avatar
unknown
haskell
2 years ago
1.5 kB
26
Indexable
Never
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}

module Bank where

import Data.Text

data AccountKind = A | B | C deriving Show

data AccountId (kind :: AccountKind) where
  AccountAId :: Text -> AccountId 'A

-- I find this approach better because you can have
-- different "info" types for each account type,
-- which is most likely a requirement already because
-- it's hard to imagine different account types don't have
-- different invariants
data AccountAInfo = AccountAInfo
data AccountBInfo = AccountBInfo

data Account (kind :: AccountKind) where
  AccountA :: AccountId 'A -> AccountAInfo -> Account 'A
  AccountB :: AccountId 'B -> AccountBInfo -> Account 'B

-- You could also explore something with type families
-- class Account acc where
--   data AccountId acc :: Type
--   data AccountInfo acc :: Type

-- It's only possible to call this with `AccountA`
specificAccountOperation :: Monad m => Account 'A -> m ()
specificAccountOperation (AccountA id info) = return ()

-- You'll receive a warning if you forget to handle an account type
anyAccountOperation :: Monad m => Account kind -> m ()
anyAccountOperation (AccountA id info) = return ()
anyAccountOperation (AccountB id info) = return ()

lookupAccount ::
  Monad m =>
  AccountId kind ->
  m (Maybe (Account kind))
lookupAccount accId = do
  -- You can choose how to serialize/deserialize
  -- your account ids via typeclass isntances
  -- in order to do a lookup (e.g. database, in-memory)
  return Nothing