Following up on my ambiguous question, here's a question that is probably more focused.
Consider the following code snippet form a Haskell program:
data NightWatchCommand = InvalidCommand | DownloadCommand { url :: String } | PauseCommand { gid :: String } | UnpauseCommand { gid :: String } | StatusCommand { gid :: String } deriving (Show, Eq)
data AuthNightwatchCommand = AuthNightwatchCommand {
command :: NightWatchCommand,
user :: User
}
Now, the business constraint I want to enforce via the type-system is this: it should not be possible to instantiate an unauthenticated NightwatchCommand
. And the only way to instantiate an AuthNightwatchCommand
should be via a special function, say:
fromIncomingMsg :: String -> AuthNightwatchCommand
Just to provide greater context, the string argument to this function could possibly be:
status <some-id> <auth-token>
Now, to complicate matters further, fromIncomingMsg
needs to validate the <auth-token>
from the DB. Which means, it will do IO. A more appropriate function signature would be:
fromIncomingMsg :: String -> IO (AuthNightwatchCommand)
Apart from shoving this into a module and hiding the data constructors, is there any other way to do this?
Authorized
, which has a methodString -> IO a
. Now, functions should only deal with things of type(forall a. Authorized a => a)
. Even if something makes a fraudulentAuthorized
, nothing can make a fraudulent(forall a. Authorized a => a)
.) – PyRulez Jan 25 '16 at 18:52Authenticable
that allows instances to harness common code while still hiding their data constructors (and the details of their individual logic) in modules. Having a lot of modules is not necessarily a bad thing; a lot of large Haskell projects seem to have many. I think modules are intended to be used for encapsulation. – mdunsmuir Jan 25 '16 at 23:18