Swift µframework of simple functional programming tools

Overview

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 reimplement them for each consumer, I am gathering them here together.

Notably, this framework does not provide any new types, or any functions which operate on custom types; those presumably belong in µframeworks of their own.

Table of Contents

Gallery

Prelude’s functions are infinitely useful. Here’s a gallery of just a few of the things you can do with them.

id

Passing id as the argument to the flattenMap method of a Stream of Streams will flatten it out into a stream of all the nested elements:

func flatten<T>(stream: Stream<Stream<T>>) -> Stream<T> {
	return stream.flattenMap(id)
}

const

Passing the result of const to an Either is convenient for transforming it into an Optional<T>:

let result: Either<NSError, String> = 
if let string = result.either(const(nil), id) {
	println("ohai \($0)")
}

>>> and <<<

The left-to-right and right-to-left composition operators (>>> and <<< respectively) chain operations together:

let repl: File -> String = readLine >>> parseString >>> evaluateAST >>> toString
while true {
	println(repl(standardInput))
}

fix

You can use fix to make an anonymous function which calls itself recursively:

let factorial = fix { recur in
	{ n in n > 0 ? n * recur(n - 1) : 1 }
}

|> and <|

The forward and backward application operators (|> and <| respectively) apply the function on the side they’re pointing at to the value on the other side.

This can sometimes make code more readable. This is particularly the case for the forward application operator. x |> f is equivalent to f(x), but it reads in the direction that the data flows. The benefit is more obvious with longer function names:

100 |> toString |> count // => 3
// this is equivalent to
countElements(toString(100))

Backward application reads in the wrong direction for this—f <| x isn’t really any improvement on f(x). Unlike forward application, however, <| can apply binary and ternary functions to their first operands. This enables you to make something like Haskell’s operator sections:

let successor: Int -> Int = (+) <| 1
successor(3) // => 4
map([1, 2, 3], (*) <| 2) // => [2, 4, 6]

You can also combine |> and <| with flip to pass data through chains of higher-order functions like sorted, map, and reduce:

let result =
	[66, 78, 1, 95, 76]
|>	(flip(sorted) <| (<)) // sort in ascending order
|>	(flip(map) <| toString) // make them into strings
|>	String.join(", ") // comma-separate them

let sum: [Int] -> Int = flip(reduce) <| (+) <| 0

Since Swift functions can also be applied to tuples of their arguments, you can also use |> and <| with binary, ternary, etc. functions just by placing a tuple on the other side:

(1, 2) |> (+) // => 3

curry

Currying takes a function of >1 parameter and returns a function of one parameter which returns a function of one parameter, and so on. That is, given (T, U) -> V, currying returns T -> U -> V.

This is particularly useful when making more interesting functions such as <|.

flip

Faux operator sectioning using <| might be a little surprising using non-commutative operators like - and /: (-) <| 1 means { 1 - $0 }, which is very different from { $0 - 1 }. You can use flip to produce the latter:

map([1, 2, 3], (-) <| 1) // => [0, -1, -2]
map([1, 2, 3], flip(-) <| 1) // => [0, 1, 2]

&&&

Optional has a map method which is just what you need when you want to apply a function to a value if non-nil, or return nil otherwise. When you have two Optional values, you can use &&& to combine them:

let (x: Int?, y: Int?) = (2, 2)
(x &&& y).map(+) // => .Some(4)

swap

Swift’s tuples are very convenient, but sometimes when you get one, it’s the wrong way around. swap does to tuples what flip does to functions: it reverses their order.

map(enumerate("hello"), swap) // => [(h, 0), (e, 1), (l, 2), (l, 3), (o, 4)]

first and second

Getting one value from a tuple is a common operation that can be expressed with first and second functions. Operators provide first and second values of two-elements tuple accordingly.

[(0,0), (5, 1), (9, 2)].map(second) // => [0, 1, 2]

Documentation

Full API documentation is in the source.

Integration

  1. Add this repository as a submodule and check out its dependencies, and/or add it to your Cartfile if you’re using carthage to manage your dependencies.
  2. Drag Prelude.xcodeproj into your project or workspace.
  3. Link your target against Prelude.framework.
  4. Application targets should ensure that the framework gets copied into their application bundle. (Framework targets should instead require the application linking them to include Prelude.)

Or use the Swift package manager and add this to your Package.swift file:

  ...
  dependencies: [
    ...  
    .package(url: "https://github.com/robrix/Prelude", "3.0.0" ..< "4.0.0")
  ],
  targets: [
    ...
    .target(
        name: "<YourTargetName>",
        dependencies: ["Prelude"]),
  ]
Comments
  • Carthage support?

    Carthage support?

    I already use carthage to manage the dependencies in my framework, but every time I try to run carthage update with the line

    github "robrix/Prelude" == 1.1
    

    in my Cartfile, I get an error:

    Error Domain=org.carthage.ReactiveTask Code=0 "fatal: Not a git repository (or any of the parent directories): .git
    " UserInfo=0x7f9a00f0ea40 {NSLocalizedDescription=fatal: Not a git repository (or any of the parent directories): .git
    , ReactiveTaskErrorExitCode=128, ReactiveTaskErrorStandardError=fatal: Not a git repository (or any of the parent directories): .git
    }
    

    But again, only when I try to add Prelude. Have you experienced this?

    opened by justinmakaila 10
  • Low precedence right associative application (Haskell `$`)

    Low precedence right associative application (Haskell `$`)

    Status quo

    By analogy with F# (see F# Symbol and Operator Reference) the backward pipe <| operator in this library has low precedence and right associativity. This kind of function application operator is of limited usefulness, because it doesn't allow consecutive application without extra parentheses.

    Compare:

    • F#, direct function application
    > List.sum (List.take 2 (1 :: [2; 3])) ;;
    val it : int = 3
    
    • F#, backward pipe operator
    > List.sum <| (List.take 2 <| 1 :: [2; 3]) ;;
    val it : int = 3
    
    • F#, high precedence right associative backward pipe operator
    > let inline (^<|) f a = f a ;;
    > List.sum ^<| List.take 2 ^<| 1 :: [2; 3] ;;
    val it : int = 3
    
    • Haskell, direct function application:
    > sum (take 2 (1 : [2, 3]))
    3
    
    > sum $ take 2 $ 1 : [2, 3]
    3
    

    Notice that the right associative function application operator allows to drop the maximum possible number of parentheses (often all).

    Proposal

    Lets introduce a low precedence right associative function application operator to allow more concise and expressive code!

    How to name it?

    F# ^<| intuitively connects with the left associative variant (<|), but originally it is a high precedence operator.

    Haskell $ is very concise and defines exactly the low precedence right associative function application operator, thus it seems to be the best choice.

    opened by werediver 6
  • Backward pipe operator has got right associativity.

    Backward pipe operator has got right associativity.

    Solves issue #55 by changing the backward pipe <| operator associativity from left to right.

    Version changed from 1.6.0 to 1.7.0 in podspec (minor update). Should we make a major update instead?

    opened by werediver 5
  • cleanup / #43 | Deprecated `unit`

    cleanup / #43 | Deprecated `unit`

    As suggested in #43 unit deprecated in honor of Optional.Some. Documentation removed. Unit-test removed, to avoid deprecation warning during compilation. I believe it is legit, as there are no guarantees anymore on the workability of deprecated functionality, as well as no plans to support it in future. unit should be removed completely in the future major release.

    opened by nikita-leonov 5
  • Forward application variant for piping through `T -> ()` functions.

    Forward application variant for piping through `T -> ()` functions.

    This adds a variant of the forward application operator for T -> () functions, allowing you to strap side effects to an expression instead of having to drop into an imperative style. While this definitely has some 🙊 factor (and isn't technically forward application?), it really nicely handles a somewhat common desire when dealing with Cocoa's objectiveyness: expressing instances that have a few customized properties as a single expression.

    For example, check out how great declaring lazy properties can be:

    lazy var formatter = NSDateFormatter() |> {
        $0.dateFormat = "HH:mm"
        $0.timeZone = NSTimeZone(abbreviation: "GMT")
    }
    

    Or how about inlining customized objects as parameters:

    let tauDay = calendar.dateFromComponents(NSDateComponents() |> {
        $0.month = 6
        $0.day = 28
        $0.year = 2031
    })
    

    It's also useful for stuff outside of object setup (though this strikes me as a practice that could get messy fast). Here's adding logging to an expression that's being returned, without having to change return e into let result = e; log(result); return result... or remember how to do this with Xcode breakpoints:

    return someExpression |> { logDebug($0) }
    

    Things I'm not sure about:

    • That this is even a good idea. I really like it and have used it a decent amount already without issue, but part of me keeps thinking that this is the kind of thing that might be either terrible in ways that I'm not experienced enough to notice, or not providing enough of a marginal improvement to justify the overhead.
    • That it should reuse the operator. This seems so similar to the existing pipe forward, but is it too easy to write a closure that accidentally returns Void instead of T or T instead of Void and get unintended behavior? Using something slightly different (|>> or ||> maybe?) would let the compiler help us out.
    • That Prelude is the right place for this. To this outside observer Prelude looks like a good home, and it mostly fits the goals stated in the README (except for authorship), but it also feels slightly out of place as the only impure function in the framework.

    So basically, everything(?).

    Thoughts?

    (Also, totes apologies if just dropping into your project and hollering "Hey, what do you think of this?" with a slightly long rambly pr is a faux pas... or just rude)

    opened by kazmasaurus 5
  • Curried flip?

    Curried flip?

    Take this (not so) hypothetical implementation of a Schwartzian transform that makes use of curried, flipped versions of some standard library functions:

    func sortedBy<S: SequenceType, Key>(seq: S, key: S.Generator.Element -> Key) -> [S.Generator.Element] {
      return lazy(seq)
        |> map { i in (i, key(i)) }
        |> sorted { a, b in a.1 < b.1 }
        |> map { i, _ in i }
    }
    

    Currently I need to hand-write those curried, flipped versions of map and sorted.

    Given that Prelude already provides |> and <|, making this kind of chaining possible—would it also sense to have a combined curry & flip function? Then this would be achievable using only Prelude, like so:

    func sortedBy<S: SequenceType, Key>(seq: S, key: S.Generator.Element -> Key) -> [S.Generator.Element] {
      return lazy(seq)
        |> flip(map) { i in (i, key(i)) }
        |> flip(sorted) { a, b in a.1 < b.1 }
        |> flip(map) { i, _ in i }
    }
    

    I'm not sure if you'd really want to overload the existing flip function as implied here, but perhaps there's an alternative name?

    opened by sharplet 4
  • 1.7.0 doesn't conform to semantic versioning

    1.7.0 doesn't conform to semantic versioning

    The release is dedicated for Swift 3 and apparently breaks the backwards compatibility: https://github.com/robrix/Prelude/releases/tag/1.7.0. That should be tagged as 2.0.0.

    @robrix @335g

    opened by ikesyo 3
  • Tuple extraction operators.

    Tuple extraction operators.

    Sorry that it took so long. It was hard to find even a second recent weeks.

    Btw in our code base we have third defined, as well as first & second defined for a three elements tuples. Do you think it can be helpful for other people? Is it a good practice in general to have three elements tuples in a code or it is already a reason to create struct?

    Also since we have three elements tuples we have functions dropFirst, dropSecond and dropLast to convert three-element tuple to two-elements tuples. I will be happy to contribute it as well if it lies in a scope of this project.

    opened by nikita-leonov 3
  • Why there is no fst, snd?

    Why there is no fst, snd?

    Thanks for the work so far! It helps a lot. We were writing our own prelude, but it seems redundant when this uframework in place.

    In our implementation we have fst & snd for tuple unwraps. It known Haskell functions that allows to avoid in place anonymous functions like { $0 } or { $0.0 } etc. We have a code guidelines to prefer functions & functions compositions in our code instead of closures. It would be great to have such functions in Prelude. What do you think? I can provide PR if proposal sounds reasonable.

    opened by nikita-leonov 2
  • Added swift version for cocoapods.

    Added swift version for cocoapods.

    CocoaPods does not use project file settings as guidance to compile specs, as result require additional guidance which Swift version to use. This PR provides .swift-version file that informs CocoaPods to use 3.0 swift for this Podspec.

    opened by nikita-leonov 1
  • Adds podspec

    Adds podspec

    This adds a pod spec to the repository for version 1.5.0.

    This also allows to use Prelude as

    pod 'Prelude', :git => 'https://github.com/robrix/Prelude.git'
    
    opened by angerman 1
  • Flipping curried functions.

    Flipping curried functions.

    By default, Swift provides all entity functions as curried static functions so calls to entity functions can be represented in a two ways:

    //regular use
    let something: Something = ...
    something.map { ... }
    //curried function use
    Something.map(something)({ ... })
    

    The existing implementation of flip works only on uncurried functions, while there are a lot of use cases for a curried version of flip. Does it make sense to introduce a curried version of flip?

    opened by nikita-leonov 2
  • const overload accepting a closure for memoized lazy evaluation

    const overload accepting a closure for memoized lazy evaluation

    I think const might be more useful if it were marked as @autoclosure(escaping). As it is, you can’t use it for any kind of effectful case analysis because effects occur regardless of the branch taken, which defeats the purpose of using case analysis for effects.

    opened by robrix 4
Releases(3.0.1)
Owner
Rob Rix
Colouring outside the lines at @GitHub.
Rob Rix
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
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
🏹 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
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 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
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
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
Functional data types and functions for any project

Swiftx Swiftx is a Swift library containing functional abstractions and extensions to the Swift Standard Library. Swiftx is a smaller and simpler way

TypeLift 219 Aug 30, 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
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
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
A simple integrated version of iOS 13 Compositional Layout, modified into a way similar to Functional Programming to generate UICollectionViewCompositionalLayout.

WWCompositionalLayout A simple integrated version of iOS 13 Compositional Layout, modified into a way similar to Functional Programming to generate UI

William-Weng 1 Jul 4, 2022
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
Keep It Functional - An iOS Functional Testing Framework

IMPORTANT! Even though KIF is used to test your UI, you need to add it to your Unit Test target, not your UI Test target. The magic of KIF is that it

KIF Framework 6.2k Dec 29, 2022
adb-tools-mac is a macOS menu bar app written in SwiftUI for common adb tools.

adb-tools-mac is a macOS menu bar app written in SwiftUI for common adb tools.

Naman Dwivedi 930 Jan 2, 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 Dec 25, 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
🏹 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