Skip to content

Commit

Permalink
Add randomness
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Sep 17, 2018
1 parent f1f0bc5 commit e134dfc
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 0 deletions.
14 changes: 14 additions & 0 deletions 0030-composable-randomness/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [DSLs vs. Templating Languages](https://www.pointfree.co/episodes/ep29-dsls-vs-templating-languages)
>
> Templating languages are the most common way to render HTML in web frameworks, but we don’t think they are the best way. We compare templating languages to the DSL we previously built, and show that the DSL fixes many problems that templates have, while also revealing amazing compositions that were previously hidden.
### Getting Started

* Clone repo
* `cd` into this directory
* Run `make`
* Open `TemplatingLanguages.xcworkspace`
* Build `cmd+B`
* Open the playground
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@

import Darwin
arc4random()

arc4random() % 6 + 1

arc4random_uniform(6) + 1

// 1984-2018

arc4random_uniform(2018 + 1 - 1984) + 1984

func arc4random_uniform(between a: UInt32, and b: UInt32) -> UInt32 {
return arc4random_uniform(b + 1 - a) + a
}

arc4random_uniform(between: 1984, and: 2018)

UInt32.random(in: 1984...2018)
UInt32.random(in: .min ... .max)


UInt.random(in: 1984...2018)
UInt.random(in: .min ... .max)

Int.random(in: 1984...2018)
Int.random(in: .min ... .max)

//Int.random(in: 0..<0)


enum Move: CaseIterable {
case rock, paper, scissors
}

Move.allCases

Move.allCases[Int(arc4random_uniform(UInt32(Move.allCases.count)))]

func arc4random_uniform<A>(element xs: [A]) -> A {
return xs[Int(arc4random_uniform(UInt32(xs.count)))]
}

arc4random_uniform(element: Move.allCases)

//arc4random_uniform(element: [])

print(Move.allCases.randomElement())
[].randomElement()


Double.random(in: 0...1)
Bool.random()

arc4random() % 2 == 0

arc4random

// () -> UInt32
// (UInt32) -> Double

//let uniform = arc4random >>> { Double($0) / Double(UInt32.max) }
//uniform(())

struct Gen<A> {
let run: () -> A
}

let random = Gen { arc4random() }
random.run()

struct Func<A, B> { let run: (A) -> B }

extension Gen {
func map<B>(_ f: @escaping (A) -> B) -> Gen<B> {
return Gen<B> { f(self.run()) }
}
}

random.map(String.init).run()

let uniform = random.map { Double($0) / Double(UInt32.max) }

uniform.run()
uniform.run()
uniform.run()

func double(in range: ClosedRange<Double>) -> Gen<Double> {
return uniform.map { t in
t * (range.upperBound - range.lowerBound) + range.lowerBound
}
}

double(in: -2...10).run()
double(in: -2...10).run()
double(in: -2...10).run()
double(in: -2...10).run()

Double.random(in: -2...10)

let uint64: Gen<UInt64> = .init {
let lower = UInt64(random.run())
let upper = UInt64(random.run()) << 32
return lower + upper
}

uint64.run()
uint64.run()
uint64.run()
uint64.run()

func int(in range: ClosedRange<Int>) -> Gen<Int> {
return .init {
var delta = UInt64(truncatingIfNeeded: range.upperBound &- range.lowerBound)
if delta == UInt64.max {
return Int(truncatingIfNeeded: uint64.run())
}
delta += 1
let tmp = UInt64.max % delta + 1
let upperBound = tmp == delta ? 0 : tmp
var random: UInt64 = 0
repeat {
random = uint64.run()
} while random < upperBound
return Int(
truncatingIfNeeded: UInt64(truncatingIfNeeded: range.lowerBound)
&+ random % delta
)
}
}

int(in: -2...10).run()
int(in: -2...10).run()
int(in: -2...10).run()
int(in: -2...10).run()

let roll = int(in: 1...6)

let bool = int(in: 0...1).map { $0 == 1 }
bool.run()
bool.run()
bool.run()
Bool.random()

func element<A>(of xs: [A]) -> Gen<A?> {

return int(in: 0...(xs.count - 1)).map { idx in
guard !xs.isEmpty else { return nil }
return xs[idx]
}
}

let move = element(of: Move.allCases)
.map { $0! }
move.run()
move.run()
move.run()

Bool.random
//[Element].random

extension Gen {
// func array(count: Int) -> Gen<[A]> {
// return Gen<[A]> {
// Array(repeating: (), count: count).map(self.run)
// }
// }

func array(count: Gen<Int>) -> Gen<[A]> {
return Gen<[A]> {
Array(repeating: (), count: count.run()).map(self.run)
}
// return count.map { self.array(count: $0).run() }
}
}

let rollPair = roll.array(count: .init { 2 })
rollPair.run()
rollPair.run()
rollPair.run()
rollPair.run()

let aFewMoves = move.array(count: int(in: 0...3))
aFewMoves.run()
aFewMoves.run()
aFewMoves.run()
aFewMoves.run()

// huwKun-1zyjxi-nyxseh

let chars = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")

let alphanum = element(of: chars).map { $0! }

let passwordSegment = alphanum.array(count: .init { 6 })
.map { $0.map(String.init).joined() }

let password = passwordSegment.array(count: .init { 3 })
.map { $0.joined(separator: "-") }

password.run()
password.run()
password.run()
password.run()
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*:
# DSLs vs. Templating Languages

## Exercises

1.) Create a function called `frequency` that takes an array of pairs, `[(Int, Gen<A>)]`, to create a `Gen<A>` such that `(2, gen)` is twice as likely to be run than a `(1, gen)`.
*/
// TODO
/*:
2.) Extend `Gen` with an `optional` computed property that returns a generator that returns `nil` a quarter of the time. What other generators can you compose this from?
*/
// TODO
/*:
3.) Extend `Gen` with a `filter` method that returns a generator that filters out random entries that don't match the predicate. What kinds of problems may this function have?
*/
// TODO
/*:
4.) Create a `string` generator of type `Gen<String>` that randomly produces a randomly-sized string of any unicode character. What smaller generators do you composed it from?
*/
// TODO
/*:
5.) Redefine `element(of:)` to work with any `Collection`. Can it also be redefined in terms of `Sequence`?
*/
// TODO
/*:
6.) Create a `subsequence` generator to return a randomly-sized, randomly-offset subsequence of an array. Can it be redefined in terms of `Collection`?
*/
// TODO
/*:
7.) The `Gen` type has `map` defined it, which, as we've seen in the past, allows us to consider what `zip` might look like. Define `zip2` on `Gen`:

func zip2<A, B>(_ ga: Gen<A>, _ gb: Gen<B>) -> Gen<(A, B)>
*/
// TODO
/*:
8.) Define `zip2(with:)`:

func zip2<A, B, C>(with f: (A, B) -> C) -> (Gen<A>, Gen<B>) -> Gen<C>
*/
// TODO
/*:
9.) With `zip2` and `zip2(with:)` defined, define higher-order `zip3` and `zip3(with:)` and explore some uses. What functionality does `zip` provide our `Gen` type?
*/
// TODO
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

precedencegroup ForwardCompose {
associativity: left
}
infix operator >>>: ForwardCompose
public func >>> <A, B, C>(f: @escaping (A) -> B, g: @escaping (B) -> C) -> (A) -> C {
return { g(f($0)) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<playground version='6.0' target-platform='macos' display-mode='rendered'>
<pages>
<page name='01-episode'/>
<page name='02-exercises'/>
</pages>
</playground>
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ This repository is the home of code written on episodes of
1. [Domain Specific Languages: Part 2](0027-edsls-pt2)
1. [An HTML DSL](0028-html-dsl)
1. [DSLs vs. Templating Languages](0029-dsls-vs-templating-languages)
1. [Composable Randomness](0030-composable-randomness)

0 comments on commit e134dfc

Please sign in to comment.