Created
May 6, 2015 10:45
-
-
Save alskipp/d1ba93366f93135c5ed0 to your computer and use it in GitHub Desktop.
A safe version of Haskell’s foldl1 for Swift (+ minBy & maxBy functions)
This file contains hidden or 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
/* | |
Pipe forward operator: | |
Applies the function on the right to the value on the left | |
*/ | |
infix operator |> {associativity left precedence 95} | |
func |> <A,B>(x:A, f:A -> B) -> B { | |
return f(x) | |
} | |
/* | |
Haskell’s foldl1, but safe. | |
The default implementation for Haskell will error on an empty List | |
This version avoids the potential error by returning an Optional | |
*** | |
It's just like 'reduce', but doesn't require an initial value | |
*/ | |
func reduce1<A>(f:(A,A) -> A)(_ xs:[A]) -> A? { | |
return first(xs).map { x in | |
reduce(xs[1..<xs.endIndex], x, f) | |
} | |
} | |
// Examples of reduce1 | |
reduce1(*)([1,2,3,4]) // 24 | |
let a:[Int] = [] | |
reduce1(+)(a) // .None | |
reduce1(+)(["hello ", "world"]) // "hello world" | |
/* | |
Using 'reduce1' it is now possible to implement 'minBy' & 'maxBy' | |
*/ | |
func minBy<A,B:Comparable>(f:A -> B)(xs:[A]) -> A? { | |
return xs |> reduce1 { x,y in f(x) < f(y) ? x : y } | |
} | |
func maxBy<A,B:Comparable>(f:A -> B)(xs:[A]) -> A? { | |
return xs |> reduce1 { x,y in f(x) > f(y) ? x : y } | |
} | |
/* | |
Examples of 'minBy' & 'maxBy' | |
We need a data structure to test: a Monster will do. | |
*/ | |
struct Monster { | |
let name:String, eyes:Int, limbs:Int, teeth:Int | |
} | |
let monsters = [ | |
Monster(name: "Bob", eyes: 1, limbs: 4, teeth: 32), | |
Monster(name: "Fred", eyes: 8, limbs: 8, teeth: 0), | |
Monster(name: "Jill", eyes: 2, limbs: 64, teeth: 8) | |
] | |
let eyes = monsters |> maxBy { $0.eyes } | |
eyes // {name "Fred", eyes 8, limbs 8, teeth 0} | |
let limbs = monsters |> maxBy { $0.limbs } | |
limbs // {name "Jill", eyes 2, limbs 32, teeth 8} | |
let teeth = monsters |> maxBy { $0.teeth } | |
teeth // {name "Bob", eyes 1, limbs 4, teeth 32} | |
let fewestTeeth = monsters |> minBy { $0.teeth } | |
fewestTeeth // {name "Fred", eyes 8, limbs 8, teeth 0} | |
let noMonsters:[Monster] = [] | |
noMonsters |> maxBy { $0.limbs } // .None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment