diff --git a/Runes.xcodeproj/project.pbxproj b/Runes.xcodeproj/project.pbxproj index 67755a7..4e15f7f 100644 --- a/Runes.xcodeproj/project.pbxproj +++ b/Runes.xcodeproj/project.pbxproj @@ -39,6 +39,10 @@ F8DDC6EB1DD6755300E173E0 /* Optional+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6E91DD6754600E173E0 /* Optional+Alternative.swift */; }; F8DDC6EC1DD6755300E173E0 /* Optional+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6E91DD6754600E173E0 /* Optional+Alternative.swift */; }; F8DDC6ED1DD6755400E173E0 /* Optional+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6E91DD6754600E173E0 /* Optional+Alternative.swift */; }; + F8DDC6EF1DD67D2600E173E0 /* Array+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */; }; + F8DDC6F01DD67D2900E173E0 /* Array+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */; }; + F8DDC6F11DD67D2A00E173E0 /* Array+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */; }; + F8DDC6F21DD67D2B00E173E0 /* Array+Alternative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */; }; F8E09D1D1DCF83F200816E60 /* Array+Applicative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E09D151DCF83F200816E60 /* Array+Applicative.swift */; }; F8E09D1E1DCF83F200816E60 /* Array+Applicative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E09D151DCF83F200816E60 /* Array+Applicative.swift */; }; F8E09D1F1DCF83F200816E60 /* Array+Applicative.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8E09D151DCF83F200816E60 /* Array+Applicative.swift */; }; @@ -149,6 +153,7 @@ F89AAC911D74D00E00184D08 /* Mozart.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mozart.framework; sourceTree = ""; }; F89AAC931D74D01A00184D08 /* Mozart.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Mozart.framework; path = Carthage/Build/iOS/Mozart.framework; sourceTree = SOURCE_ROOT; }; F8DDC6E91DD6754600E173E0 /* Optional+Alternative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Optional+Alternative.swift"; sourceTree = ""; }; + F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Alternative.swift"; sourceTree = ""; }; F8E09D151DCF83F200816E60 /* Array+Applicative.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Applicative.swift"; sourceTree = ""; }; F8E09D161DCF83F200816E60 /* Array+Functor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Functor.swift"; sourceTree = ""; }; F8E09D171DCF83F200816E60 /* Array+Monad.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Monad.swift"; sourceTree = ""; }; @@ -335,6 +340,7 @@ F8E09D141DCF83F200816E60 /* Array */ = { isa = PBXGroup; children = ( + F8DDC6EE1DD67D2600E173E0 /* Array+Alternative.swift */, F8E09D151DCF83F200816E60 /* Array+Applicative.swift */, F8E09D161DCF83F200816E60 /* Array+Functor.swift */, F8E09D171DCF83F200816E60 /* Array+Monad.swift */, @@ -640,6 +646,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F8DDC6F11DD67D2A00E173E0 /* Array+Alternative.swift in Sources */, F8E09D2B1DCF83F200816E60 /* Optional+Applicative.swift in Sources */, F8E09D331DCF83F200816E60 /* Optional+Monad.swift in Sources */, F8E09D1F1DCF83F200816E60 /* Array+Applicative.swift in Sources */, @@ -665,6 +672,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F8DDC6F21DD67D2B00E173E0 /* Array+Alternative.swift in Sources */, F8E09D2C1DCF83F200816E60 /* Optional+Applicative.swift in Sources */, F8E09D341DCF83F200816E60 /* Optional+Monad.swift in Sources */, F8E09D201DCF83F200816E60 /* Array+Applicative.swift in Sources */, @@ -680,6 +688,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F8DDC6EF1DD67D2600E173E0 /* Array+Alternative.swift in Sources */, F8E09D291DCF83F200816E60 /* Optional+Applicative.swift in Sources */, F8E09D311DCF83F200816E60 /* Optional+Monad.swift in Sources */, F8E09D1D1DCF83F200816E60 /* Array+Applicative.swift in Sources */, @@ -715,6 +724,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F8DDC6F01DD67D2900E173E0 /* Array+Alternative.swift in Sources */, F8E09D2A1DCF83F200816E60 /* Optional+Applicative.swift in Sources */, F8E09D321DCF83F200816E60 /* Optional+Monad.swift in Sources */, F8E09D1E1DCF83F200816E60 /* Array+Applicative.swift in Sources */, diff --git a/Sources/Runes/Array/Array+Alternative.swift b/Sources/Runes/Array/Array+Alternative.swift new file mode 100644 index 0000000..1d29485 --- /dev/null +++ b/Sources/Runes/Array/Array+Alternative.swift @@ -0,0 +1,22 @@ +/** + Return the result of concatenating two arrays + + - parameter lhs: A value of type `[T]` + - parameter rhs: A value of type `[T]` + + - returns: The result of concatenating `lhs` and `rhs` +*/ +public func <|> (lhs: [T], rhs: @autoclosure () -> [T]) -> [T] { + return lhs + rhs() +} + +/** + Return an empty context of `[]` + + This is the dual of `pure`. + + - returns: An instance of `[]` of the type `[T]` +*/ +public func empty() -> [T] { + return [] +} diff --git a/Tests/RunesTests/ArraySpec.swift b/Tests/RunesTests/ArraySpec.swift index 5d08cb5..2e8265a 100644 --- a/Tests/RunesTests/ArraySpec.swift +++ b/Tests/RunesTests/ArraySpec.swift @@ -90,6 +90,29 @@ class ArraySpec: XCTestCase { } } + func testAlternative() { + property("alternative operator - left empty") <- forAll { (x: Int) in + let lhs: [Int] = empty() <|> pure(x) + let rhs: [Int] = pure(x) + + return lhs == rhs + } + + property("alternative operator - right empty") <- forAll { (x: Int) in + let lhs: [Int] = pure(x) <|> empty() + let rhs: [Int] = pure(x) + + return lhs == rhs + } + + property("alternative operator - neither empty") <- forAll { (x: Int, y: Int) in + let lhs: [Int] = pure(x) <|> pure(y) + let rhs: [Int] = pure(x) + pure(y) + + return lhs == rhs + } + } + func testMonad() { // return x >>= f = f x property("left identity law") <- forAll { (x: Int, fa: ArrowOf) in