
Hi Francesco,
You won't have a concrete type for every combination of constraints. For
the most part, your programs will all end up in IO (or some transformer
over IO) anyway. I usually have a "test" transformer and a "production"
transformer (both of which are usually ReaderT Env IO), and instances
defined for each.
It's OK to pass an overly large record to a function. A common style is to
write a huge `data Env = Env { ... }` with dozens of fields, and use
classes to only access the things you need. This allows you to pass smaller
Envs in, but it doesn't require that you write dozens of types preemptively.
I would suggest that `MonadTime` and `MonadKeys` are not great choice for a
Layer 2 - it would be really difficult to write a mock for MonadKeys that
was in any way meaningful. I'd suggest restricting these classes to be
tightly coupled to your domain problem. Instead of getting random keys, try
a sum-type with all the possible things you'd prompt the user for, and a
type for possible user responses. This is much easier to mock meaningfully.
Matt Parsons
On Sun, May 19, 2019 at 4:25 AM Francesco Ariis
(literate Haskell follows)
Hello -cafe, I recently read "Three Layer Haskell Cake" [1] and decided to give it a go. I am stuck on a simple problem and feel like I am missing something easy. One of the first examples is a mocking of an `IO UTCTime` function.
{-# Language FlexibleInstances #-}
data UTCTime = UTCTime Int
class MonadTime m where getCurrentTime :: m UTCTime
instance MonadTime ((->) UTCTime) where getCurrentTime = id
-- instance IO omitted
Everything is clear. I decided to write another function, mocking a stream-of-Char input.
class MonadKeys m where getKeys :: m [Char]
instance MonadKeys ((->) [Char]) where getKeys = id
-- instance IO omitted
Again, fine. But now, if I want to write a function which combines the two external services, like:
someFun :: (MonadTime m, MonadKeys m) => m () someFun = undefined
there is no non-IO instance satisfying the two constraints. I could of course write a type
data Env = Env UTCTime [Char]
and make it instance of MonadTime and MonadKeys, but then I am passing non-relevant arguments to a mocked function like getCurrentTime, which would only need UTCTime.
What am I doing incorrectly? -F
[1] https://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.