Infix operators for monadic functions in Swift

Overview

Indecipherable symbols that some people claim have actual meaning.

pod Carthage compatible Swift Package Manager compatible

Please see the documentation for installation instructions.

What's included?

Importing Runes introduces several new operators and one global function that correspond to common Haskell typeclasses:

Functor

  • <^> (pronounced "map")

Applicative Functor

  • <*> (pronounced "apply")
  • <* (pronounced "left sequence")
  • *> (pronounced "right sequence")
  • pure (pronounced "pure")

Alternative

  • <|> (pronounced "alternate")
  • empty (pronounced "empty")

Monad

  • >>- (pronounced "flatMap") (left associative)
  • -<< (pronounced "flatMap") (right associative)
  • >-> (pronounced "Monadic compose") (left associative)
  • <-< (pronounced "Monadic compose") (right associative)

Implementations

We also include default implementations for Optional and Array with the following type signatures:

// Optional+Functor:
public func <^> <T, U>(f: T -> U, x: T?) -> U?

// Optional+Applicative:
public func <*> <T, U>(f: (T -> U)?, x: T?) -> U?
public func <* <T, U>(lhs: T?, rhs: U?) -> T?
public func *> <T, U>(lhs: T?, rhs: U?) -> U?
public func pure<T>(x: T) -> T?

// Optional+Alternative:
public func <|> <T>(lhs: T?, rhs: T?) -> T?
public func empty<T>() -> T?

// Optional+Monad:
public func >>- <T, U>(x: T?, f: T -> U?) -> U?
public func -<< <T, U>(f: T -> U?, x: T?) -> U?
public func >-> <T, U, V>(f: T -> U?, g: U -> V?) -> T -> V?
public func <-< <T, U, V>(f: U -> V?, g: T -> U?) -> T -> V?

// Array+Functor:
public func <^> <T, U>(f: T -> U, x: [T]) -> [U]

// Array+Applicative:
public func <*> <T, U>(fs: [T -> U], x: [T]) -> [U]
public func <* <T, U>(lhs: [T], rhs: [U]) -> [T]
public func *> <T, U>(lhs: [T], rhs: [U]) -> [U]
public func pure<T>(x: T) -> [T]

// Array+Alternative:
public func <|> <T>(lhs: [T], rhs: [T]) -> [T]
public func empty<T>() -> [T]

// Array+Monad:
public func >>- <T, U>(x: [T], f: T -> [U]) -> [U]
public func -<< <T, U>(f: T -> [U], x: [T]) -> [U]
public func >-> <T, U, V>(f: T -> [U], g: U -> [V]) -> T -> [V]
public func <-< <T, U, V>(f: U -> [V], g: T -> [U]) -> T -> [V]

// Result+Functor:
public func <^> <T, U, E>(f: (T) -> U, a: Result<T, E>) -> Result<U, E>

// Result+Applicative:
public func <*> <T, U, E>(f: Result<(T) -> U, E>, a: Result<T, E>) -> Result<U, E>
public func <* <T, U, E>(lhs: Result<T, E>, rhs: Result<U, E>) -> Result<T, E>
public func *> <T, U, E>(lhs: Result<T, E>, rhs: Result<U, E>) -> Result<U, E>
public func pure<T, E>(_ a: T) -> Result<T, E>

// Result+Alternative:
public func <|> <T, E>(lhs: Result<T, E>, rhs: @autoclosure () -> Result<T, E>) -> Result<T, E>

// Result+Monad:
public func >>- <T, U, E>(a: Result<T, E>, f: (T) -> Result<U, E>) -> Result<U, E>
public func -<< <T, U, E>(f: (T) -> Result<U, E>, a: Result<T, E>) -> Result<U, E>
public func >-> <T, U, V, E>(f: @escaping (T) -> Result<U, E>, g: @escaping (U) -> Result<V, E>) -> (T) -> Result<V, E>
public func <-< <T, U, V, E>(f: @escaping (U) -> Result<V, E>, g: @escaping (T) -> Result<U, E>) -> (T) -> Result<V, E>

Contributing

See the CONTRIBUTING document. Thank you, contributors!

License

Runes is Copyright (c) 2015 thoughtbot, inc. It is free software, and may be redistributed under the terms specified in the LICENSE file.

About

thoughtbot

Runes is maintained and funded by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.

We love open source software! See our other projects or look at our product case studies and hire us to help build your iOS app.

Comments
  • Move from Fox to SwiftCheck

    Move from Fox to SwiftCheck

    I really like SwiftCheck's syntax more then Fox. And this removes a metric fuckload of overhead, since it becomes the only dependency.

    Right now, this is pointed at master, because I need a new release of SwiftCheck that doesn't conflict with the operators we define.

    See https://github.com/typelift/SwiftCheck/issues/100 for more info.

    opened by gfontenot 14
  • Add Applicative `*>`, `<*`, and Alternative `<|>` operators

    Add Applicative `*>`, `<*`, and Alternative `<|>` operators

    This pull request adds new Applicative *>, <*, and Alternative <|> operators, which are needed feature in https://github.com/tryswift/TryParsec/pull/11 and all other functional libraries :sparkles: (See also: #65)

    By the way, Argo is currently using the same <|> operator in Alternative.swift#L13 with precedence 140, but this causes continuous monadic operations not working nicely. For example, m1 *> m2 <|> m3 *> m4 doesn't work and must use parenthesis to work around like (m1 *> m2) <|> (m3 *> m4), which is very cumbersome. Since Haskell uses lower precedence for <|>, I have dropped it down to precedence 120 (or, precedence 125 might be a better choice as discussed in https://github.com/tryswift/TryParsec/pull/11).

    I also added comments about Haskell's infix operator precedences for comparison with Runes :eyes:

    opened by inamiy 8
  • Curried functions to be removed in a later version of Swift

    Curried functions to be removed in a later version of Swift

    Greetings.

    Presently, I'm implementing Runes like so in my app:

    import Argo
    import Runes
    
    public struct Product {
        public let name: String
        public let price: NSDecimalNumber
        public let code: String
        public let balanceIncrease: Double?
        public let discount: NSDecimalNumber?
    
        public init(name: String, price: NSDecimalNumber, code: String, balanceIncrease: Double?, discount: NSDecimalNumber?) {
            self.name = name
            self.price = price
            self.code = code
            self.balanceIncrease = balanceIncrease
            self.discount = discount
        }
    }
    
    extension Product: Decodable {
        private static func create(name: String)(price: NSDecimalNumber)(code: String)(balanceIncrease: Double?)(discount: NSDecimalNumber?) -> Product {
            return Product(name: name, price: price, code: code, balanceIncrease: balanceIncrease, discount: discount)
        }
    
        public static func decode(json: JSON) -> Decoded<Product> {
            return Product.create
                <^> json <| "name"
                <*> json <| "price"
                <*> json <| "code"
                <*> json <|? "balance_increase"
                <*> json <|? "discount"
        }
    }
    
    extension Product: Equatable { }
    public func ==(lhs: Product, rhs: Product) -> Bool {
        return lhs.name == rhs.name && lhs.price == rhs.price && lhs.code == rhs.code && lhs.balanceIncrease == rhs.balanceIncrease
    }
    
    extension Product: CustomStringConvertible {
        public var description: String {
            return "Product <name: \(self.name), price: \(self.price), code: \(code), balanceIncrease: \(balanceIncrease)>"
        }
    }
    

    But in extension Product: Decodable I am making use of curried functions to achieve what I need. Apparently curried syntax is being removed, so going forward, would you have any suggestions on how I would achieve similar results without function currying?

    opened by asowers1 7
  • Various fixes

    Various fixes

    This includes a few things. Some minor (formatting, SwiftCheck update), some larger (Extension API across all targets, updates for newest version of Swift 3)

    Don't know how I feel about these precedence groups, tbh. I don't think I feel super great about them. Our tests are also completely broken, since it's apparently impossible to resolve the differences between how we're choosing to define these operators and how SwiftCheck defines them. No idea what to do about this.

    Fixes #59 Fixes #78

    opened by gfontenot 6
  • Monadic composition

    Monadic composition

    Monadic composition

    Here's how I'm using this with Result and RAC:

    request(.GET, "/myendpoint")
      .flatMap(.Concat, transform: SignalProducer.init • (parseJSON >-> decodeSomething))
    

    Basically, this really helps to avoid explicit closures everywhere, which I value for both readability and the avoidance of capturing strong references to self.


    The composition operator

    In the example above I'm using as the composition operator (which can be typed on US keyboards with Opt-8). I threw this into the specs for this PR, because I think it really helps their clarity.

    I'd love your feedback on:

    • Whether you agree about the improvement to the specs
    • What you think about adding this to the public API of Runes in a subsequent commit
    opened by sharplet 6
  • Prevent incorrect use of `flatMap`

    Prevent incorrect use of `flatMap`

    Swift will happily coerce functions of the type A -> B into functions of the type A -> B?. That means that using flatMap with a function that doesn't return an optional will compile. But then at runtime, you will run into weird behaviour that you don't expect, or worse, Swift will segfault.

    In order to prevent these problems from happening in the future, we're going to throw errors ourselves if flatMap is used incorrectly with a message letting the user know that the type of the function isn't correct. Using a default (but ultimately unused) implementation of map will push people in the right direction if they go digging.

    Credit to @mattrubin for the idea: https://github.com/thoughtbot/Argo/issues/34#issuecomment-70166588

    opened by gfontenot 6
  • What about default implementations for SequenceType?

    What about default implementations for SequenceType?

    Notes regarding <*>: It doesn't seem possible to create a generic type constraint over a sequence of A -> B, so this version uses [A -> B] as a workaround (which is no problem when combined with <^>, which returns an Array). i.e., Swift borks at this:

    func <*> <F: SequenceType, S: SequenceType, A, B where F.Generator.Element == A -> B, S.Generator.Element == A> (fs: F, source: S) -> [B] {
                                                                                  ^^^^^^ NOPE
    

    I didn't think too hard about style, naming, etc., that's all up for grabs! Just keen to know if you're into this idea.

    opened by sharplet 6
  • Adding tvOS support

    Adding tvOS support

    Rebased against your master branch. Built all schemes of Runes from a dependent library (Argo) to test, and that was successful.

    I recognize this will require developers to use Xcode 7.1, so just let me know if you've got different ideas about where this might want to go.

    opened by bruceflowers 5
  • Remove guards for `flatMap`

    Remove guards for `flatMap`

    Looks like Apple fixed the automatic coercion of T -> U into T -> U? that was causing us issues with flatMap. Since the compiler no longer allows this, we don't need to guard against it manually.

    enhancement help wanted 
    opened by gfontenot 5
  • Change SwiftCheck dependency as private

    Change SwiftCheck dependency as private

    It seems SwiftCheck has been introduced since v4.2.2, and it is affecting end users to always pull its unnecessary repository via Swift Package Manager:

    $ cd my-project-using-runes/
    $ swift build
    Updating https://github.com/thoughtbot/Runes.git
    Fetching [email protected]:typelift/SwiftCheck.git
    ...
    

    I have tried both Xcode 10 (Swift 5.0) and Xcode 11 Beta (Swift 5.1), but result was the same. It's probably due to Swift Package Manager still not able to handle test dependencies nicely.

    I think there needs some workaround e.g. https://github.com/pointfreeco/swift-snapshot-testing/issues/201 . What do you think?

    opened by inamiy 4
  • @autoclosure in Swift 5

    @autoclosure in Swift 5

    In Sources/Runes/Optional/Optional+Alternative.swift:14 an @autclosure block is passed as an argument. This is forbidden in Swift 5.

    From Swift 5 release notes:

    In Swift 5 mode, @autoclosure parameters can no longer be forwarded to @autoclosure arguments in another function call. Instead, you must explicitly call the function value with parentheses: (); the call itself is wrapped inside an implicit closure, guaranteeing the same behavior as in Swift 4 mode. (SR-5719) (37321597)

    Is there any solution for this?

    opened by madcato 4
  • Add a release script

    Add a release script

    I'd like to be able to automate the release of this lib, so that we don't forget to do things like add tags, release to CocoaPods, etc. We should script this.

    opened by gfontenot 0
Releases(v5.1.0)
  • v5.1.0(May 22, 2020)

    This small release adds support for Swift 5.2 tooling, which means that if you're using Swift 5.2 you'll no longer see our test dependencies downloaded locally when you're just trying to annoy your coworkers with illegible code like a normal person.

    Source code(tar.gz)
    Source code(zip)
  • v5.0.0(Jun 1, 2019)

    This release adds operator definitions for the new Result<T, E> type in Swift 5's stdlib. Accordingly, Runes 5.0 drops support for Swift versions lower than 5.0.

    Source code(tar.gz)
    Source code(zip)
  • v4.2.2(May 30, 2019)

    This is a bug fix release to fix a compiler error that occured under Swift 5.0 when we tried to pass an autoclosure directly to another argument expecting an autoclosure, which is now disallowed. (Thanks @madcato!) This change should be backwards compatible with previous Swift versions.

    Source code(tar.gz)
    Source code(zip)
  • v4.2.1(Mar 19, 2019)

  • v4.2.0(Mar 15, 2019)

  • v4.1.1(Apr 15, 2018)

    This updates the Xcode project (and some internal dependencies) so that no warnings are thrown by the Xcode project.

    This will almost certainly mean nothing to you, unless you import this project into your project, in which case this will mean everything

    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(Jun 7, 2017)

    This release fleshes out the rest of the Applicative implementations for Optional and Array. This adds two new operators to the mix for each type:

    • <* performs an applicative operation, discarding the right hand value
    • *> performs an applicative operation, discarding the left hand value

    We're also adding full implementations for Alternative for both types:

    • <|> performs an alternative operation
    • empty constructs an empty value (basically the dual of pure)
    • Optional now has an .or instance method that acts as a named version of <|>.
    Source code(tar.gz)
    Source code(zip)
  • v4.0.1(Nov 5, 2016)

    4.0.1 fixes issues with building Runes via Swift Package Manager that were caused by a change in the way SPM expected test directories to be structured.

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Oct 12, 2016)

  • v3.2.1(Jul 22, 2016)

    3.2.1 adds better support for Xcode 8 and Swift 2.3 by recording these preferences in the project file. This will be the last release to support Swift 2.X, and master will move forward with Swift 3.0 support.

    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Jan 15, 2016)

  • v3.1.0(Oct 30, 2015)

  • v3.0.0(Sep 18, 2015)

    • [NEW]: Swift 2.0 support
    • [NEW]: watchOS targets for Carthage and CocoaPods
    • [NEW]: Optional.apply and Array.apply are now publicly available instance methods
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-rc.2(Jul 15, 2015)

    This makes it easier to add Runes to your framework as a light weight internal dependency for introducing the operators for your own types.

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-rc.1(Jul 15, 2015)

  • v2.0.0(May 4, 2015)

    This release refines the precedence for our operators to bring them in line with Haskell's implementation.

    • The map (<^>) and apply (<*>) operators now have a precedence of 130. This gives them an equal precedence with Swift's built in equality operator (==)
    • The flatMap operators (>>- and -<<) now have a precedence of 100. This gives them a precedence higher than the assignment operator (=), but lower than the or operator (||).

    Note that this change flips the precedence of these operators. Previous releases gave flatMap a higher precedence than map and apply. Updating to 2.0.0 might require the addition/removal of parenthesis in your code to return to the intended behavior.

    Huge thanks to @sharplet for the research (and implementation) behind this change.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(Mar 13, 2015)

  • v1.2.1(Mar 13, 2015)

    This release removes the implementations of flatMap for Optionals and Arrays. flatMap is now included in the standard library for both of these types, so we don't need to duplicate their implementations here.

    This release also adds a flipped operator for flatMap (-<<) and removes the guards around improper use of flatMap. These guards were needed to avoid segfaults in the compiler, but the compiler is now preventing the improper use of this operator itself.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Mar 13, 2015)

  • v1.2.0(Feb 16, 2015)

    This release is intended to be used with Swift 1.2. There are no actual changes since Runes 1.1.1, but the attached binary has been built with the Swift 1.2 compiler.

    This release will not work with Swift versions 1.2 beta 3 and beyond due to the introduction of flatMap into the standard library

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Feb 16, 2015)

    This release adds a protective ~~spell~~ compiler annotation to ensure that flatMap isn't used where map should be used. This is to prevent the Swift compiler from "helping" and coercing functions of the type A -> B to A -> B? and causing a segfault.

    Source code(tar.gz)
    Source code(zip)
  • v1.1(Feb 16, 2015)

  • v1.0(Feb 16, 2015)

Owner
thoughtbot, inc.
We work with organizations of all sizes to design, develop, and grow their web and mobile products.
thoughtbot, inc.
Functional chaining and promises in Swift

Forbind Functional chaining and promises in Swift Note: still in an experimental state. Everything could change. I would love some feedback on this. W

Ulrik Flænø Damm 45 Sep 1, 2022
Functional programming tools and experiments in Swift.

Funky The documentation (courtesy of realm/jazzy) is available here: https://brynbellomy.github.io/Funky Master branch is currently compatible with: S

Bryn Bellomy 12 May 2, 2017
Collection of must-have functional Swift tools

NOTE: This project has been merged with and superceded by Rob Rix's Result µframework. LlamaKit Collection of must-have functional tools. Trying to be

null 619 Aug 5, 2022
A functional utility belt implemented as Swift 2.0 protocol extensions.

Oriole [![CI Status](http://img.shields.io/travis/Tyler Thompson/Oriole.svg?style=flat)](https://travis-ci.org/Tyler Thompson/Oriole) Oriole is a set

Tyler Paul Thompson 11 Aug 10, 2019
Swift µframework of simple functional programming tools

Prelude This is a Swift µframework providing a number of simple functions that I use in many of my other frameworks. Rather than continue to reimpleme

Rob Rix 405 Jun 29, 2022
Functional programming in Swift

Swiftz Swiftz is a Swift library for functional programming. It defines functional data structures, functions, idioms, and extensions that augment the

TypeLift 3.3k Dec 25, 2022
Swift µframework with extensions for the Optional Type

OptionalExtensions Why? Swift's Optional is pretty awesome, but it can always get better. This repository is an humble attempt to add some utility met

Rui Peres 183 Dec 15, 2022
Functional JSON parsing library for Swift

Argo Argo is a library that lets you extract models from JSON or similar structures in a way that's concise, type-safe, and easy to extend. Using Argo

thoughtbot, inc. 3.5k Jan 7, 2023
🏹 Bow is a cross-platform library for Typed Functional Programming in Swift

Bow is a cross-platform library for Typed Functional Programming in Swift. Documentation All documentation and API reference is published in our websi

Bow 613 Dec 20, 2022
Functional programming in Swift

Swiftz Swiftz is a Swift library for functional programming. It defines functional data structures, functions, idioms, and extensions that augment the

TypeLift 3.3k Jan 6, 2023
A set of Swift extensions for standard types and classes.

ExSwift Set of Swift extensions for standard types and classes. Installation Because of Xcode errors it's not possible to integrate this project with

Pierluigi D'Andrea 3.4k Dec 27, 2022
Infix operators for monadic functions in Swift

Indecipherable symbols that some people claim have actual meaning. Please see the documentation for installation instructions. What's included? Import

thoughtbot, inc. 825 Dec 7, 2022
🎯 PredicateKit allows Swift developers to write expressive and type-safe predicates for CoreData using key-paths, comparisons and logical operators, literal values, and functions.

?? PredicateKit PredicateKit is an alternative to NSPredicate allowing you to write expressive and type-safe predicates for CoreData using key-paths,

Faiçal Tchirou 352 Jan 3, 2023
Swift Custom Operators for Mathematical Notation

Euler Euler uses custom operators in the "Math Symbols" character set to implement functions using traditional mathematical notation. Please keep in m

Mattt 1.1k Jan 4, 2023
AsyncExtensions aims to mimic Swift Combine operators for async sequences.

AsyncExtensions AsyncExtensions provides a collection of operators, async sequences and async streams that mimics Combine behaviour. The purpose is to

AsyncCommunity 200 Dec 27, 2022
A collection of operators and utilities that simplify iOS layout code.

Anchorage A lightweight collection of intuitive operators and utilities that simplify Auto Layout code. Anchorage is built directly on top of the NSLa

Rightpoint 620 Jan 3, 2023
ProgrammingCalculator - a simple programmer's calculator with operators like AND, OR

Programmer's Calculator This is a simple calculator program which implements operators commonly used in discrete logic such as AND, OR, Bit Shifting,

Austin Wright 0 Jan 5, 2022
Azure Functions in Swift! Purely in Swift!

Azure Functions for Swift ⚡️ Write Azure Functions in Swift. This framework supports the new Azure Functions Custom Handlers (starting from 0.6.0) in

Saleh Albuga 87 Jan 3, 2023
Sweet-swift - Make Swift Sweet by Gracefully Introducing Syntactic Sugar, Helper Functions and Common Utilities

Sweet Swift Make Swift Sweet by Gracefully Introducing Syntactic Sugar, Helper F

Yanzhan Yang 2 Feb 6, 2022
CryptoSwift - Crypto related functions and helpers for Swift implemented in Swift

CryptoSwift Crypto related functions and helpers for Swift implemented in Swift.

Kushal Shingote 2 Feb 6, 2022