Functional architecture is Ports and Adapters (2016)
blog.ploeh.dk
blog.ploeh.dk
checkCapacity' :: forall f. Functor f => Int -> (ZonedTime -> f Int) -> Reservation -> f (Either Error Reservation)
you can guarantee that any effects in the final result only come from the function you supplied to it, i.e. checkCapacity' cannot add any effects of its own(Also, it can only "run" the function exactly once).The type of the arguments of checkCapacity' are also a strict generalisation of the arguments to
checkCapacity :: Int -> (ZonedTime -> IO Int) -> Reservation -> Either Error Reservation
meaning that any valid arguments to checkCapacity are valid for checkCapacity' as well. checkCapacity :: Int -> (ZonedTime -> IO Int) -> Reservation -> IO (Either Error Reservation)(Functional Core, Imperative Shell is often linked with Hexagonal / Onion / Ports and Adapters. It is a bit more opinionated about using values as boundaries I believe ... and I think it is right).
EDIT: TFA is a good article, worth reading.
Ultimately none of these patterns matter. The design philosophy that underlies them (separation of concerns, for example) does. It's something that becomes self-evident as you progress from junior to senior and beyond. We as an industry seem to love telling each other how our way is the one true way.
I understood the only purpose of writing the Haskell was didactic, and to improve his F# code. It seems that moving further from constructs in F# would work against this.