I have the following (simple) data structure:
struct Work<Input, Output> {
let work: Input -> Output
}
This type represents work which can take an Input
and turns in into a desired Output
. I am trying to see whether this data structure conforms to some functional concepts like a functor or a monad.
Functor
extension Work {
func map<MoreOutput>(transform: Output -> MoreOutput) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> {
return transform(self.work($0))
}
}
}
That seems to be correct as far as I am aware. I am able to write a map function which can turn Work<Input, Output>
into Work<Input, MoreOutput>
Monad
I have trouble thinking of the definition for a flatMap
(or fold
) function for Work
. The only thing I can come up with is the following:
extension Work {
func flatMap<MoreOutput>(transform: Work<Output, MoreOutput>) -> Work<Input, MoreOutput> {
return Work<Input, MoreOutput> { input in
return transform.work(self.work(input))
}
}
}
If you look up the flatMap
definition for an Array
in swift it looks like this (simplified):
func flatMap(transform: (Element) -> T?) -> [T]
This is a function where its argument is a function which transforms an Element
into T
and results an Array
. I cannot think of a way to abstract this to the Work
type.
From another functional book I found a general definition for flatMap as follows (on an object F
holding type A
):
func flatMap<B>(f: A -> F<B>) -> F<B>
which is a different definition of flatMap
than Array
seems to implement.
Can someone explain this difference to me? And is it even possible to define a 'correct' flatMap
function on Work
? Or does Work
not satisfy the properties to be a Monad?
** Edit
Thanks phg for so much useful info. I've tried to do the Profunctor definition:
Making Work
a Profunctor
:
extension Work {
func diMap<A, B>(fa: A -> Input, fb: Output -> B) -> Work<A, B> {
return Work<A, B> { arg in
let input = fa(arg)
let output = self.work(input)
return fb(output)
}
}
}
Does that look right to you?