6 ms·
I successfully got the Functor example to work like this: protocol Functor { typealias T typealias FunctorResult func map<P>(mappin
by jmah 12y ago
I successfully got the Functor example to work like this:
protocol Functor {
typealias T
typealias FunctorResult
func map<P>(mappingFunction: T -> P) -> FunctorResult
}
extension Dictionary : Functor {
func map<P>(mappingFunction: ValueType -> P) -> Dictionary<KeyType, P> {
var newDict:Dictionary<KeyType, P> = [:]
for (key, value) in self {
newDict[key] = mappingFunction(value)
}
return newDict
}
}
- afthonos 12y agoThat doesn't actually work, because you're limiting the return type of the method in the implementation of the functor. So by implementing that protocol, you could have one mapping from Int to String (say), but not another from Int to Double. Put another way, you need to specify FunctorResult at implementation time, and the whole point is to only have to specify it at call time.
- jmah 12y agoThis code works: let d = [1: 1, 2: 2, 3: 3] let intToInt = d.map { $0 + 1 } var IntToString = d.map { String($0) }
- afthonos 12y agoThe code works, but the type of the generic is not guaranteed at compile time. FunctorResult could be anything at all. There is no compile-time obligation for the code to return a Dictionary<KeyType, P>. The more canonical example of a Functor is really the Optional. The mapping method for an optional looks like this: func fmap(f: A -> B) -> Optional<B> { switch self { case Some(let a): return Some(f(A)) case None: return None } } However, with your protocol, I can define the mapping function for the Optional as: func fmap(f: A -> B) -> B[] { switch self { case Some(let a): return [f(A)] case None: return B[]() } } This would pass the type-checker, but is not what a Functor does.
- barrkel 12y agoIt's hard to implement generic functors as a protocol without either runtime code generation or generalized dynamic dispatch. The typical efficient implementation of a protocol (aka an interface) is a vtable - an array of pointers to functions. When you instantiate a generic in a statically compiled language, that usually clones the body of the generic thing (method or type) with references to the generic parameters replaced with the type arguments; and the new, cloned body is handed off to codegen. But if you instantiate via a protocol reference, the compiler doesn't statically know the implementation of the thing you're trying to call - it can't see the body of code to clone. It's an indirect function call through a variable, and without a restricted language, analyzing it quickly runs into the halting problem. With runtime code generation, the problem can be solved with sufficient magic - the runtime can rewrite as necessary. That's how .NET implements this. Alternatively, if the body of each generic method is compiled using some form of dynamic dispatch - e.g. every operation on a value whose type is a generic parameter is done via an table of function pointers, and this table is passed into the generic method at the point of every call - then it can work, at some cost in speed. Haskell works like this, AIUI. Java does it even more simply, with full-fat dynamic dispatch - all generic parameters turn into Object, and method bodies get runtime casts inserted as necessary.
- platz 12y agoSome folks are working on a library for this already: https://github.com/maxpow4h/swiftz https://github.com/maxpow4h/swiftz
- maxpow4h 12y agoyup. we have a "Functor" https://github.com/maxpow4h/swiftz/blob/master/swiftz/Unsound/Functor.swift https://github.com/maxpow4h/swiftz/blob/master/swiftz/Unsoun... It requires constructing a "Functor" value manually, otherwise it works fine. You can still write functions over an A in Functor. The Result enum bug presented you can work around by boxing the type, such as in https://github.com/maxpow4h/swiftz/blob/master/swiftz/List.swift https://github.com/maxpow4h/swiftz/blob/master/swiftz/List.s... The third problem a work around exists for: remove the default argument. If you want an empty init, provide one. Sure it is buggy, but you can express these programs.
- afthonos 12y agoThanks for the Box suggestion; I'll try it and see how it works for me. I wouldn't have thought of that workaround.