I’m trying to write a utility method that is kind of the opposite of “x ?? y”, which means “x != nil ? x : y”. I want “x != nil ? f(x) : nil” This is not difficult to write, but if you have "f(x)->z" and "g(x)->z?", I seem to need two versions of the function in order to handle it. Is there any way to do this with only one function?
public func fnil<XType,RetType> (
_ x:XType?,
_ f:(XType)->RetType
)
-> RetType?
{
if let x = x {
return f(x)
} else {
return nil
}
}
public func fnil<XType,RetType> (
_ x:XType?,
_ g:(XType)->RetType?
)
-> RetType?
{
if let x = x {
return g(x)
} else {
return nil
}
}
private func f(_ x:Int) -> Int {
return x
}
private func g(_ x:Int) -> Int? {
if x == 5 {
return nil
} else {
return x
}
}
1) What you want to do is a common operation in functional programming called flatMap. Optional type already supports it. To get “x != nil ? f(x) : nil” you say:
x.flatMap(f)
2) You don’t need multiple versions, because there is a subtype-supertype relationship between functions: You need to specify the most general signature in your single function. The most general form of the function is:
(XType) throws -> RetType?
To handle throwing case, you will need to define the return type of your own function as:
fnil<...> (...) rethrows -> RetType?
Then it will accept any of the following signatures and it just works:
On Jan 11, 2018, at 5:55 PM, Kenny Leung via swift-users <swift-users@swift.org> wrote:
Hi All.
I’m trying to write a utility method that is kind of the opposite of “x ?? y”, which means “x != nil ? x : y”. I want “x != nil ? f(x) : nil” This is not difficult to write, but if you have "f(x)->z" and "g(x)->z?", I seem to need two versions of the function in order to handle it. Is there any way to do this with only one function?
public func fnil<XType,RetType> (
_ x:XType?,
_ f:(XType)->RetType
)
-> RetType?
{
if let x = x {
return f(x)
} else {
return nil
}
}
public func fnil<XType,RetType> (
_ x:XType?,
_ g:(XType)->RetType?
)
-> RetType?
{
if let x = x {
return g(x)
} else {
return nil
}
}
private func f(_ x:Int) -> Int {
return x
}
private func g(_ x:Int) -> Int? {
if x == 5 {
return nil
} else {
return x
}
}
Yep, it looks like Optional.flatmap() is what I need. Thanks!
-Kenny
···
On Jan 11, 2018, at 6:55 PM, Hooman Mehr <hooman@mac.com> wrote:
Hi,
Two points:
1) What you want to do is a common operation in functional programming called flatMap. Optional type already supports it. To get “x != nil ? f(x) : nil” you say:
x.flatMap(f)
2) You don’t need multiple versions, because there is a subtype-supertype relationship between functions: You need to specify the most general signature in your single function. The most general form of the function is:
(XType) throws -> RetType?
To handle throwing case, you will need to define the return type of your own function as:
fnil<...> (...) rethrows -> RetType?
Then it will accept any of the following signatures and it just works:
On Jan 11, 2018, at 5:55 PM, Kenny Leung via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
Hi All.
I’m trying to write a utility method that is kind of the opposite of “x ?? y”, which means “x != nil ? x : y”. I want “x != nil ? f(x) : nil” This is not difficult to write, but if you have "f(x)->z" and "g(x)->z?", I seem to need two versions of the function in order to handle it. Is there any way to do this with only one function?
public func fnil<XType,RetType> (
_ x:XType?,
_ f:(XType)->RetType
)
-> RetType?
{
if let x = x {
return f(x)
} else {
return nil
}
}
public func fnil<XType,RetType> (
_ x:XType?,
_ g:(XType)->RetType?
)
-> RetType?
{
if let x = x {
return g(x)
} else {
return nil
}
}
private func f(_ x:Int) -> Int {
return x
}
private func g(_ x:Int) -> Int? {
if x == 5 {
return nil
} else {
return x
}
}