Last active
December 28, 2017 21:46
-
-
Save TizianoCoroneo/7567c0377b7cecf12230d11324956ed4 to your computer and use it in GitHub Desktop.
Haskell style List Comprehensions in Swift 4
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
import Foundation | |
typealias Format<A, B> = Component<A, B> | |
typealias Source<A> = Component<A, A> | |
typealias Filter<A> = Component<A, A> | |
enum Component<A, B> { | |
case format((A) -> B) | |
case sources([A]) | |
case filter((A) -> Bool) | |
} | |
struct ListComprehension<A, B> { | |
let formats: [Format<A, B>] | |
let sources: [Source<A>] | |
let filters: [Filter<A>] | |
var elements: [A] { | |
return sources.map { | |
switch $0 { | |
case .sources(let elems): return elems | |
default: return [] | |
} | |
}.reduce([], +) | |
} | |
var filterFunctions: [(A) -> Bool] { | |
return self.filters.map { | |
switch $0 { | |
case .filter(let fil): return [fil] | |
default: return [] | |
} | |
}.reduce([], +) | |
} | |
var filteredElements: [A] { | |
return elements.filter { el in | |
return filterFunctions.map { filter in | |
return filter(el) | |
}.reduce(true, { $0 && $1 }) | |
} | |
} | |
var result: [B] { | |
return filteredElements.flatMap { el in | |
return formats.flatMap { format in | |
switch format { | |
case .format(let f): | |
return f(el) | |
default: | |
return nil | |
} | |
} | |
} | |
} | |
struct Compute { | |
let comprehension: ListComprehension<A, B> | |
} | |
} | |
precedencegroup ListComponents { | |
higherThan: ListCreate | |
} | |
precedencegroup ListCreate {} | |
infix operator |: ListCreate | |
prefix operator <- | |
infix operator &&&: ListComponents | |
prefix operator ?! | |
prefix operator % | |
prefix operator |- | |
postfix operator -| | |
func |<A, B>(_ lhs: Format<A, B>, _ rhs: [Component<A, A>]) -> ListComprehension<A, B> { | |
return ListComprehension(formats: [lhs], sources: rhs, filters: rhs) | |
} | |
func |<A, B>(_ lhs: [Format<A, B>], _ rhs: [Component<A, A>]) -> ListComprehension<A, B> { | |
return ListComprehension(formats: lhs, sources: rhs, filters: rhs) | |
} | |
func |<A, B>(_ lhs: [Format<A, B>], _ rhs: Component<A, A>) -> ListComprehension<A, B> { | |
return ListComprehension(formats: lhs, sources: [rhs], filters: [rhs]) | |
} | |
func |<A, B>(_ lhs: Format<A, B>, _ rhs: Component<A, A>) -> ListComprehension<A, B> { | |
return ListComprehension(formats: [lhs], sources: [rhs], filters: [rhs]) | |
} | |
prefix func |-<A, B>(_ rhs: ListComprehension<A, B>) -> ListComprehension<A, B>.Compute { | |
return ListComprehension<A, B>.Compute.init(comprehension: rhs) | |
} | |
prefix func |-<A, B>(_ rhs: () -> ListComprehension<A, B>) -> ListComprehension<A, B>.Compute { | |
return |-rhs() | |
} | |
prefix func |-<A, B>(_ rhs: ListComprehension<A, B>.Compute) -> [B] { | |
return rhs.comprehension.result | |
} | |
postfix func -|<A, B>(_ lhs: ListComprehension<A, B>) -> ListComprehension<A, B>.Compute { | |
return ListComprehension<A, B>.Compute.init(comprehension: lhs) | |
} | |
postfix func -|<A, B>(_ lhs: () -> ListComprehension<A, B>) -> ListComprehension<A, B>.Compute { | |
return lhs()-| | |
} | |
postfix func -|<A, B>(_ lhs: ListComprehension<A, B>.Compute) -> [B] { | |
return lhs.comprehension.result | |
} | |
func &&&<A, B>(_ lhs: [Component<A, B>], _ rhs: Component<A, B>) -> [Component<A, B>] { | |
return lhs + [rhs] | |
} | |
func &&&<A, B>(_ lhs: Component<A, B>, _ rhs: Component<A, B>) -> [Component<A, B>] { | |
return [lhs, rhs] | |
} | |
func &&&<A, B>(_ lhs: Component<A, B>, _ rhs: [Component<A, B>]) -> [Component<A, B>] { | |
return [lhs] + rhs | |
} | |
func &&&<A, B>(_ lhs: [Component<A, B>], _ rhs: [Component<A, B>]) -> [Component<A, B>] { | |
return lhs + rhs | |
} | |
prefix func <-<A>(_ c: [A]) -> Source<A> { | |
return Source<A>.sources(c) | |
} | |
prefix func ?!<A>(_ filter: @escaping (A) -> Bool) -> Filter<A> { | |
return Filter<A>.filter(filter) | |
} | |
prefix func %<A, B>(_ f: @escaping (A) -> B) -> Format<A, B> { | |
return Format<A, B>.format(f) | |
} | |
let formats = %{ $0 * $0 } &&& %{ $0 + 1 } | |
let sources = <-Array(1..<10) &&& <-[20, 30, 40] | |
let filters = ?!{ $0 % 2 == 0 } &&& ?!{ $0 != 4 } | |
let list = formats | sources &&& filters | |
let result = |-list-| | |
let result2: [Int] = |-{ %{$0} | <-[1, 2, 3, 4, 5] &&& ?!{ $0 % 2 == 0 } }-| |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment