I was studying a functor and monad. So I got to know that a functor uses map and a monad uses flatMap, and also that definition of map and flatMap looks like below.
enum Box<T> {
case some(T)
case empty
}
extension Box {
func map<U>(_ f: #escaping (T) -> U) -> Box<U> {
// ...
}
}
extension Box {
func flatMap<U>(_ f: (T) -> Box<U>) -> Box<U> {
// ...
}
}
I totally got those are using different f parameter(Thanks for this article).
Then, I just wanted to check definition of map and flatMap in Optional, Result and Array. Because I heard those are monad as well. In Optional and Result, the definition looks like same as custom map and flatMap above.
But in Array, does not.
func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
I'm bit confused now. Because I knew a monad apply a function that returns wrapped value to wrapped value, so I expected the definition of flatMap looking like below(definitely wrong).
func flatMap<T>(_ transform: (Element) throws -> [T]) rethrows -> [T]
But It's not anyway.
Am I missing something? Where is the point that I misunderstood?
You were expecting
func flatMap<T>(_ transform: (Element) throws -> Array<T>) rethrows -> Array<T>
for Array.
If you look closely, the above is merely a special case of the signature that you found, when SegmentOfResult == Array<T>.
The flatMap in Array is defined not just for the case when SegmentOfResult == Array<T>, but also for any SegmentOfResult that is a Sequence.
Why? Because we would like to define functions so that they work on as many types as possible (i.e. as general as possible). It turns out that flatMap would also work if the function mapped to any Sequence. That is, it doesn't depend on the fact that the function returns specifically an Array. It only depends on the fact that the function returns some kind of a Sequence. Check out how flatMap is implemented here if you are interested.
For the same reason, flatMap isn't just available on Array, it's available on any type that conforms to Sequence!
Related
Please consider the following code:
protocol P {}
class X {}
class Y: P {}
func foo<T>(_ closure: (T) -> Void) { print(type(of: closure)) }
func foo<T>(_ closure: (T) -> Void) where T: P { print(type(of: closure)) }
let xClosure: (X?) -> Void = { _ in }
foo(xClosure) // prints "(Optional<X>) -> ()"
let yClosure: (Y?) -> Void = { _ in }
foo(yClosure) // prints "(Y) -> ()"
Why does the foo(yClosure) call resolve to the version of foo constrained to T: P?
I understand why that version prints what it prints,
what I don't see is why it gets called instead of the other one.
To me it seems that the non-P version would be a better match for T == (Y?) -> Void.
Sure, the constrained version is more specific, but it requires conversion
(an implicit conversion from (Y?) -> Void to (Y) -> Void),
while the non-P version could be called with no conversion.
Is there a way to fix this code in a way such that the P-constrained version gets called
only if the parameter type of the passed-in closure directly conforms to P,
without any implicit conversions?
Specificity seems to always trump variance conversions, according to my experiments. For example:
func bar<T>(_ x: [Int], _ y: T) { print("A") }
func bar<T: P>(_ x: [Any], _ y: T) { print("B") }
bar([1], Y()) // A
bar is more specific, but requires a variance conversion from [Int] to [Any].
For why you can convert from (Y?) -> Void to (P) -> Void, see this. Note that Y is a subtype of Y?, by compiler magic.
Since it is so consistent, this behaviour seems to be by design. Since you can't really make Y not a subtype of Y?, you don't have a lot of choices if you want to get the desired behaviour.
I have this work around, and I admit it's really ugly - make your own Optional type. Let's call it Maybe<T>:
enum Maybe<T> {
case some(T)
case none
// implement all the Optional methods if you want
}
Now, your (Maybe<Y>) -> Void won't be converted to (P) -> Void. Normally I wouldn't recommend this, but since you said:
in the real-world code where I encountered this, the closure has multiple params, any of them can be optional, so this would lead to a combinatorial explosion.
I thought reinventing Optional might be worth it.
Given:
class Elem {
func f() -> AnotherElem {
return AnotherElem(elem: self)
}
}
I want to call the map function on array of Elems passing the function f:
Sample code:
collection.map { $0.f() }
However, I don't like this {} notation so I was thinking whether or not I can pass a function as an argument (which in my eyes increases readability), and indeed I can
What I want is to do the following:
collection.map(Elem.f)
The last is valid syntax however the type of the array is the following: [() -> AnotherElem] instead of expected [AnotherElem] type.
Is a bug or a feature?
Obviously, this could be solved by calling map again and calling the array of blocks, but this is not the problem I'm having.
I'm struggling to understand why it is the way it is
This is expected behaviour, i.e. not a bug.
If you try to use an instance method someMethod of the form(T) -> U directly like this:
SomeType.someMethod
The type of that expression is (SomeType) -> (T) -> U. In your case, The type of Elem.f is (Elem) -> () -> AnotherElem.
Why is it designed like this? It is so that you can pass an instance to SomeType.someMethod, and then get the original instance method:
let f = SomeType.someMethod(instanceOfSomeType)
I guess this could be somewhat called "currying".
Anyway, you would need another function to transform Elem.f:
func uncurry<T, U>(_ f: #escaping (T) -> () -> U) -> (T) -> U {
return { f($0)() }
}
Now passing uncurry(Elem.f) will work.
Here is my code:
protocol SomeProtocol {
}
class A: SomeProtocol {
}
func f1<T: SomeProtocol>(ofType: T.Type, listener: (T?) -> Void) {
}
func f2<T: SomeProtocol>(ofType: T.Type, listener: ([T]?) -> Void) {
}
func g() {
let l1: (SomeProtocol?) -> Void = ...
let l2: ([SomeProtocol]?) -> Void = ...
f1(ofType: A.self, listener: l1) // NO ERROR
f2(ofType: A.self, listener: l2) // COMPILE ERROR: Cannot convert value of type '([SomeProtocol]?) -> Void' to expected argument type '([_]?) -> Void'
}
What is the problem with the second closure having an argument of an array of generic type objects?
Swift 4.1 Update
This is a bug that was fixed in this pull request, which will make it into the release of Swift 4.1. Your code now compiles as expected in a 4.1 snapshot.
Pre Swift 4.1
This just looks like you're just stretching the compiler too far.
It can deal with conversions from arrays of sub-typed elements to arrays of super-typed elements, e.g [A] to [SomeProtocol] – this is covariance. It's worth noting that arrays have always been an edge case here, as arbitrary generics are invariant. Certain collections, such as Array, just get special treatment from the compiler allowing for covariance.
It can deal with conversions of functions with super-typed parameters to functions with sub-typed parameters, e.g (SomeProtocol) -> Void to (A) -> Void – this is contravariance.
However it appears that it currently cannot do both in one go (but really it should be able to; feel free to file a bug).
For what it's worth, this has nothing to do with generics, the following reproduces the same behaviour:
protocol SomeProtocol {}
class A : SomeProtocol {}
func f1(listener: (A) -> Void) {}
func f2(listener: ([A]) -> Void) {}
func f3(listener: () -> [SomeProtocol]) {}
func g() {
let l1: (SomeProtocol) -> Void = { _ in }
f1(listener: l1) // NO ERROR
let l2: ([SomeProtocol]) -> Void = { _ in }
f2(listener: l2)
// COMPILER ERROR: Cannot convert value of type '([SomeProtocol]) -> Void' to
// expected argument type '([A]) -> Void'
// it's the same story for function return types
let l3: () -> [A] = { [] }
f3(listener: l3)
// COMPILER ERROR: Cannot convert value of type '() -> [A]' to
// expected argument type '() -> [SomeProtocol]'
}
Until fixed, one solution in this case is to simply use a closure expression to act as a trampoline between the two function types:
// converting a ([SomeProtocol]) -> Void to a ([A]) -> Void.
// compiler infers closure expression to be of type ([A]) -> Void, and in the
// implementation, $0 gets implicitly converted from [A] to [SomeProtocol].
f2(listener: { l2($0) })
// converting a () -> [A] to a () -> [SomeProtocol].
// compiler infers closure expression to be of type () -> [SomeProtocol], and in the
// implementation, the result of l3 gets implicitly converted from [A] to [SomeProtocol]
f3(listener: { l3() })
And, applied to your code:
f2(ofType: A.self, listener: { l2($0) })
This works because the compiler infers the closure expression to be of type ([T]?) -> Void, which can be passed to f2. In the implementation of the closure, the compiler then performs an implicit conversion of $0 from [T]? to [SomeProtocol]?.
And, as Dominik is hinting at, this trampoline could also be done as an additional overload of f2:
func f2<T : SomeProtocol>(ofType type: T.Type, listener: ([SomeProtocol]?) -> Void) {
// pass a closure expression of type ([T]?) -> Void to the original f2, we then
// deal with the conversion from [T]? to [SomeProtocol]? in the closure.
// (and by "we", I mean the compiler, implicitly)
f2(ofType: type, listener: { (arr: [T]?) in listener(arr) })
}
Allowing you to once again call it as f2(ofType: A.self, listener: l2).
The listener closure in func f2<T: SomeProtocol>(ofType: T.Type, listener: ([T]?) -> Void) {...} requires its argument to be an array of T, where T is a type that implements SomeProtocol. By writing <T: SomeProtocol>, you are enforcing that all elements of that array are of the same type.
Say for example you have two classes: A and B. Both are completely distinct. Yet both implement SomeProtocol. In this case, the input array cannot be [A(), B()] because of the type constraint. The input array can either be [A(), A()] or [B(), B()].
But, when you define l2 as let l2: ([SomeProtocol]?) -> Void = ..., you allow the closure to accept an argument such as [A(), B()]. Hence this closure, and the closure you define in f2 are incompatible and the compiler cannot convert between the two.
Unfortunately, you cannot add type enforcement to a variable such as l2 as stated here. What you can do is if you know that l2 is going to work on arrays of class A, you could redefine it as follows:
let l2: ([A]?) -> Void = { ... }
Let me try and explain this with a simpler example. Let's say you write a generic function to find the greatest element in an array of comparables:
func greatest<T: Comparable>(array: [T]) -> T {
// return greatest element in the array
}
Now if you try calling that function like so:
let comparables: [Comparable] = [1, "hello"]
print(greatest(array: comparables))
The compiler will complain since there is no way to compare an Int and a String. What you must instead do is follows:
let comparables: [Int] = [1, 5, 2]
print(greatest(array: comparables))
Have nothing on Hamish's answer, he is 100% right. But if you wanna super simple solution without any explanation or code just work, when working with array of generics protocol, use this:
func f1<T: SomeProtocol>(ofType: T.Type, listener: (T?) -> Void) {
}
func f2<Z: SomeProtocol>(ofType: Z.Type, listener: ([SomeProtocol]?) -> Void) {
}
I've the following generic function (not part of any class):
func execFuncWithGenericParameter<T, U>(f: (T) -> U){
print(f("Hello World"))
}
I'd like to call this function in with a closure like this:
execFuncWithGenericParameter(f: { (p: String) -> Int in
print(p)
return 4711
})
But the compiler (iPad Swift Playground) tells me that "(String) -> U is not convertible to (T) -> U".
Naturelly I've done done some investigation and was the opinion that the Compiler automatically will infer the types.
Thanks.
The types are being inferred as far as the nature of f: (T) -> U is concerned. The problem is the call to f inside your first method.
Ask yourself: what if T were not String? Then f("Hello world") would be illegal. That is the quandary you've left the compiler with — and it rightly refuses to deal with it.
Here's a legal version:
func execFuncWithGenericParameter<T,U>(f: ((T) -> U), param:T){
f(param)
}
execFuncWithGenericParameter(f: { (p: String) -> Int in
print(p)
return 4711
}, param:"Hello")
Now the first method knows that param will be a T, so all is well. And in the second method, when we call the first method, T is String and param is a String, so it compiles (and runs, and prints).
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?
This:
func flatMap<B>(f: A -> F<B>) -> F<B>
is what you want flatMap to look like; it's the monad's usual "bind" operation. Specialized for functions over the second argument, you get the so-called Reader monad:
extension Work {
func flatMap<MoreOutput>(g: Output -> Work<Input, MoreOutput>) -> Work<Input, MoreOutput> {
// (Reader f) >>= g = Reader $ \x -> runReader (g (f x)) x
return Work<Input, MoreOutput> {
g(self.work($0)).work($0)
}
}
}
Note: I actually don't speak Swift, this code was just guessing -- hence the included Haskell original. Feel free to edit in a corrected version.
Now to the other definition:
func flatMap(transform: (Element) -> T?) -> [T]
I suppose T? means something like "optional T" or "nullable T". This is not what we usually understand as a monadic function, but it is related. Indeed, there has been a question about such "generalized flatMaps". The answer is, that if two monads are compatible, i.e., there exists a monad morphism F<A> -> G<A> preserving monadic structure, it makes sense to define
func wrappedFlatMap<B>(f: A -> F<B>) -> G<B>
which is probably exactly what is happening here for the "option type" and the list type, where the morphism is logically just
Just x ~> [x]
Nothing ~> []