I'm not sure how to express a map operator's (using <^>
rather than the traditional <$>
as <$>
doesn't compile) type signature in a way the compiler will understand. For the transformer operand the compiler complains: Cannot convert value of type '(T.Inner) throws -> U.Inner' to expected argument type '(_) throws -> _'
Where the Inner
associated type is the wrapped value of the Functor
.
I'm completely new to Swift and as a learning exercise I'm trying to build a Result
type, a Functor
protocol, and a map operator. I'm hoping the formatting is okay. My goal was to have a Result or Either type that could work like the try? operator but would return the error if an exception was thrown. Everything seems to work except for the actual operator. This is for my own learning, I understand a Result type in coming in Swift 5. Thank you for any help.
import Foundation
public protocol Functor {
associatedtype Inner
associatedtype Outer: Functor
func map<U>(
_ transform: (Inner) throws -> U
) rethrows -> Outer where Outer.Inner == U
}
precedencegroup MapPrecedence {
associativity: left
higherThan: AssignmentPrecedence
}
infix operator <^> : MapPrecedence
public func <^><T: Functor, U: Functor>(
_ transform: (T.Inner) throws -> U.Inner, rhs: T
) rethrows -> U {
return rhs.map(transform)
}
Cannot convert value of type '(T.Inner) throws -> U.Inner' to expected argument type '(_) throws -> _'
extension Optional: Functor {
public typealias Inner = Wrapped
public typealias Outer = Optional
}
extension Array: Functor {
public typealias Inner = Element
public typealias Outer = Array
}
public enum Result<Wrapped>: Functor {
public typealias Inner = Wrapped
public typealias Outer = Result
case success(Wrapped)
case error(Error)
public static func `try`(
_ runable: @autoclosure () throws -> Wrapped
) -> Result<Wrapped> {
do {
return .success(try runable())
} catch {
return .error(error)
}
}
public func map<U>(
_ transform: (Inner) throws -> U
) rethrows -> Result<U> {
switch self {
case .success(let val):
return .success(try transform(val))
case .error(let err):
return .error(err)
}
}
}