Created
January 26, 2018 21:27
-
-
Save LamourBt/39446fc6fbf8ac5f70f690f5b0b448f7 to your computer and use it in GitHub Desktop.
Functor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
An Object is considered to be a **functor** when it implements fmap (fmap referring to functor map not flatmap) | |
-[Rules] This fmap should | |
* preserve Identity (x to y) and (y to x ) should be the same value every time | |
* and be composable | |
map isn't fmap but fmap can do what map does | |
map only operates on pure function, where fmap is lifted that pure function to operate on functor type | |
*/ | |
struct Functor<A> { | |
public let value: A | |
public init(_ value: A) { self.value = value } | |
} | |
// functor extension contains default fmap implementation | |
extension Functor { | |
static func fmap<B>(_ f:@escaping (A) -> B) -> (Functor<A>) -> Functor<B> { | |
return { a in | |
return Functor<B>(f(a.value)) | |
} | |
} | |
/** | |
fmap :: (a -> b) -> f a -> f b (curried) | |
this pure function (a) -> b is going to be lifted to (f a -> f b) | |
*/ | |
public func fmap<B>(_ f:@escaping (A) -> B) -> Functor<B> { | |
return Functor<B>(f(self.value)) | |
} | |
} | |
/* | |
Since Maybe in Haskell is a functor | |
*/ | |
enum Maybe<T> { | |
case just(T), nothing | |
public init(_ value: Optional<T>) { | |
switch value { | |
case .none: self = .nothing | |
case .some(let v):self = .just(v) | |
} | |
} | |
} | |
/* | |
The example below would be a bad use/implementation of fmap, if I'm Right? | |
Because to my understanding | |
fmap takes a non-lifted pure function such as A -> B not Maybe<A> -> Maybe<B> | |
then it returns a Functor<B> | |
let something = Functor(Maybe<Int>(9)) | |
something.fmap({ x -> Maybe<Double> in | |
switch x { | |
case .nothing: return Maybe<Double>.nothing | |
case .just(let v): return Maybe<Double>(Optional<Double>(Double(v))) | |
} | |
}) | |
--- a Good example would (if I'm right of course): | |
let toDouble: (Int) -> Double = { return Double($0) } | |
let toString: (Double) -> String = { return String($0) } | |
let result = Functor(Maybe<Int>(9)).fmap(toDouble).fmap(toString) | |
*/ | |
extension Functor where A == Maybe<Any> { | |
// [constraint] if we get Functor<Maybe<Any>> you should use this version of fmap not the default fmap of Functor<B> | |
// this should be improve since `Any` kills the Type. It would be ideal if we have Maybe<Int> or Maybe<S> | |
func map(_ f:@escaping (Any) -> Any) -> Functor<Maybe<Any>> { | |
switch self.value { | |
case .just(let boxValue): | |
return Functor<Maybe<Any>>(Maybe<Any>(Optional<Any>(f(boxValue)))) | |
case .nothing: | |
return Functor<Maybe<Any>>(.nothing) | |
} | |
} | |
} | |
extension Maybe { | |
public func fmap<B>(_ f:@escaping (T) -> B) -> Functor<Maybe<B>> { | |
switch self { | |
case .just(let value): | |
return Functor<Maybe<B>>(Maybe<B>(Optional<B>(f(value)))) | |
case .nothing: | |
return Functor<Maybe<B>>(.nothing) | |
} | |
} | |
public func map<B>(_ f:@escaping (T) -> B) -> Maybe<B> { | |
switch self { | |
case .just(let value): | |
return Maybe<B>(Optional<B>(f(value))) | |
case .nothing: | |
return .nothing | |
} | |
} | |
} | |
/* Testing Identity */ | |
let negate: (Int) -> Int = { return (-1) * $0 } | |
let unnegate: (Int) -> Int = { return $0 / (-1) } | |
let intMaybe = Maybe<Int>(2) | |
let result = intMaybe.fmap(negate) | |
print(result) //Functor<Maybe<Int>>(value: __lldb_expr_115.Maybe<Swift.Int>.just(-2)) | |
let original = result.value.fmap(unnegate) | |
// result.map(<#T##f: (Any) -> Any##(Any) -> Any#>) //<-- can't use this yet since Any kills the type | |
print(original) //Functor<Maybe<Int>>(value: __lldb_expr_133.Maybe<Swift.Int>.just(2)) | |
//let fun = Maybe<Character>("C").fmap({ $0.hashValue }).map(toDouble) // <-- can't do that yet | |
//print(fun) | |
/* | |
Testing Composability | |
*/ | |
// regular map from maybe is composable | |
let some = Maybe<String>("jake") | |
.map({ $0.uppercased() }) | |
.map({ x -> Character? in return x.first }) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment