GitXplorerGitXplorer
r

Prelude

public
409 stars
26 forks
3 issues

Commits

List of commits on branch master.
Verified
a048b7af84fc25a1fd0af62e1dfe34c685cd446f

Merge pull request #61 from nxtstep/doc/swift-package-manager

rrobb committed 6 years ago
Unverified
d50ca2d308c9b6838137cdf64db2d76d5c479497

Typo

nnxtstep committed 6 years ago
Unverified
5faeee7c52e3491522ec4786781fea129efac298

Added Swift package manager install step to README

nnxtstep committed 6 years ago
Unverified
431ad7449ac0c56657a76f3a4169dd794d2d3fe1

Merge branch 'master' of github.com:robrix/Prelude

nnxtstep committed 6 years ago
Unverified
97430f158428693a252500e929dc09f22535ed25

Removed deprecated .characters

nnxtstep committed 6 years ago
Unverified
7e295402e51427eab2744ee2d4dded41c1243d87

Add Swift Package manager support

nnxtstep committed 6 years ago

README

The README file for this repository.

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"]),
  ]