Skip to content

Instantly share code, notes, and snippets.

@alskipp
Created May 6, 2015 10:45
Show Gist options
  • Save alskipp/d1ba93366f93135c5ed0 to your computer and use it in GitHub Desktop.
Save alskipp/d1ba93366f93135c5ed0 to your computer and use it in GitHub Desktop.
A safe version of Haskell’s foldl1 for Swift (+ minBy & maxBy functions)
/*
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