/0036-advanced-protocol-witnesses-pt2/Witnesses.playground/Contents.swift

https://github.com/pointfreeco/episode-code-samples · Swift · 435 lines · 284 code · 104 blank · 47 comment · 17 complexity · a530c53749e3c0ab9e820ece3494102a MD5 · raw file

  1. import Darwin
  2. struct Predicate<A> {
  3. let contains: (A) -> Bool
  4. func contramap<B>(_ f: @escaping (B) -> A) -> Predicate<B> {
  5. return Predicate<B> { self.contains(f($0)) }
  6. }
  7. func pullback<B>(_ f: @escaping (B) -> A) -> Predicate<B> {
  8. return Predicate<B> { self.contains(f($0)) }
  9. }
  10. }
  11. let isLessThan10 = Predicate { $0 < 10 }
  12. isLessThan10.contains(5)
  13. isLessThan10.contains(11)
  14. //let shortStrings = isLessThan10.contramap { (s: String) in s.count }
  15. import Overture
  16. let shortStrings = isLessThan10.contramap(get(\String.count))
  17. shortStrings.contains("Blob")
  18. shortStrings.contains("Blobby McBlob")
  19. isLessThan10.pullback(get(\String.count))
  20. struct Describing<A> {
  21. let describe: (A) -> String
  22. func contramap<B>(_ f: @escaping (B) -> A) -> Describing<B> {
  23. return Describing<B> { b in
  24. self.describe(f(b))
  25. }
  26. }
  27. func pullback<B>(_ f: @escaping (B) -> A) -> Describing<B> {
  28. return Describing<B> { b in
  29. self.describe(f(b))
  30. }
  31. }
  32. }
  33. struct PostgresConnInfo {
  34. var database: String
  35. var hostname: String
  36. var password: String
  37. var port: Int
  38. var user: String
  39. }
  40. let compactWitness = Describing<PostgresConnInfo> { conn in
  41. return "PostgresConnInfo(database: \"\(conn.database)\", hostname: \"\(conn.hostname)\", password: \"\(conn.password)\", port: \"\(conn.port)\", user: \"\(conn.user)\")"
  42. }
  43. let prettyWitness = Describing<PostgresConnInfo> {
  44. """
  45. PostgresConnInfo(
  46. database: \"\($0.database)\",
  47. hostname: \"\($0.hostname)\",
  48. password: \"\($0.password)\",
  49. port: \"\($0.port)\",
  50. user: \"\($0.user)\"
  51. )
  52. """
  53. }
  54. let secureCompactWitness = compactWitness.contramap(set(\.password, "*******"))
  55. let securePrettyWitness = prettyWitness.contramap(set(\.password, "******"))
  56. compactWitness.pullback(set(\.password, "******"))
  57. protocol Combinable {
  58. func combine(with other: Self) -> Self
  59. }
  60. struct Combining<A> {
  61. let combine: (A, A) -> A
  62. }
  63. struct EmptyInitializing<A> {
  64. let create: () -> A
  65. }
  66. let sum = Combining<Int>(combine: +)
  67. let zero = EmptyInitializing { 0 }
  68. let product = Combining<Int>(combine: *)
  69. let one = EmptyInitializing { 1 }
  70. extension Array {
  71. func reduce(_ initial: EmptyInitializing<Element>, _ combining: Combining<Element>) -> Element {
  72. return self.reduce(initial.create(), combining.combine)
  73. }
  74. }
  75. [1, 2, 3, 4].reduce(zero, sum)
  76. [1, 2, 3, 4].reduce(one, product)
  77. //extension Combining where A == Int {
  78. // static let sum = Combining(combine: +)
  79. // static let product = Combining(combine: *)
  80. //}
  81. //
  82. //extension EmptyInitializing where A == Int {
  83. // static let zero = EmptyInitializing { 0 }
  84. // static let one = EmptyInitializing { 1 }
  85. //}
  86. extension Combining where A: Numeric {
  87. static var sum: Combining {
  88. return Combining(combine: +)
  89. }
  90. static var product: Combining {
  91. return Combining(combine: *)
  92. }
  93. }
  94. extension EmptyInitializing where A: Numeric {
  95. static var zero: EmptyInitializing {
  96. return EmptyInitializing { 0 }
  97. }
  98. static var one: EmptyInitializing {
  99. return EmptyInitializing { 1 }
  100. }
  101. }
  102. [1, 2, 3, 4].reduce(EmptyInitializing.zero, Combining.sum)
  103. [1, 2, 3, 4].reduce(EmptyInitializing.one, Combining.product)
  104. [1, 2, 3, 4].reduce(.zero, .sum)
  105. [1, 2, 3, 4].reduce(.one, .product)
  106. [1.1, 2, 3, 4].reduce(.zero, .sum)
  107. [1.1, 2, 3, 4].reduce(.one, .product)
  108. extension Describing where A == PostgresConnInfo {
  109. static let compact = Describing { conn in
  110. return "PostgresConnInfo(database: \"\(conn.database)\", hostname: \"\(conn.hostname)\", password: \"\(conn.password)\", port: \"\(conn.port)\", user: \"\(conn.user)\")"
  111. }
  112. static let pretty = Describing {
  113. """
  114. PostgresConnInfo(
  115. database: \"\($0.database)\",
  116. hostname: \"\($0.hostname)\",
  117. password: \"\($0.password)\",
  118. port: \"\($0.port)\",
  119. user: \"\($0.user)\"
  120. )
  121. """
  122. }
  123. }
  124. let localhostPostgres = PostgresConnInfo(
  125. database: "pointfreeco_development",
  126. hostname: "localhost",
  127. password: "",
  128. port: 5432,
  129. user: "pointfreeco"
  130. )
  131. func print<A>(tag: String, _ value: A, _ witness: Describing<A>) {
  132. print("[\(tag)] \(witness.describe(value))")
  133. }
  134. print(tag: "debug", localhostPostgres, compactWitness)
  135. print(tag: "debug", localhostPostgres, .compact)
  136. extension Describing where A == Bool {
  137. static let compact = Describing { $0 ? "t" : "f" }
  138. static let pretty = Describing { $0 ? "𝓣𝓻𝓾𝓮" : "𝓕𝓪𝓵𝓼𝓮" }
  139. }
  140. print(tag: "debug", true, .compact)
  141. print(tag: "debug", true, .pretty)
  142. //extension Array: Equatable where Element: Equatable {
  143. //}
  144. // public protocol Equatable {
  145. // public static func == (lhs: Self, rhs: Self) -> Bool
  146. // }
  147. struct Equating<A> {
  148. let equals: (A, A) -> Bool
  149. func pullback<B>(_ f: @escaping (B) -> A) -> Equating<B> {
  150. return Equating<B> { lhs, rhs in
  151. self.equals(f(lhs), f(rhs))
  152. }
  153. }
  154. }
  155. extension Equating where A == Int {
  156. static let int = Equating(equals: ==)
  157. }
  158. extension Equating {
  159. static func array(of equating: Equating) -> Equating<[A]> {
  160. return Equating<[A]> { lhs, rhs in
  161. guard lhs.count == rhs.count else { return false }
  162. for (lhs, rhs) in zip(lhs, rhs) {
  163. if !equating.equals(lhs, rhs) {
  164. return false
  165. }
  166. }
  167. return true
  168. }
  169. }
  170. }
  171. Equating.array(of: .int).equals([], [])
  172. Equating.array(of: .int).equals([1], [1])
  173. Equating.array(of: .int).equals([1], [1, 2])
  174. let stringCount = Equating.int.pullback(get(\String.count))
  175. Equating.array(of: stringCount).equals([], [])
  176. Equating.array(of: stringCount).equals(["Blob"], ["Blob"])
  177. Equating.array(of: stringCount).equals(["Blob"], ["Bolb"])
  178. Equating.array(of: stringCount).equals(["Blob"], ["Blob Sr"])
  179. //[[Int]]
  180. [[1, 2], [3, 4]] == [[1, 2], [3, 4, 5]]
  181. [[1, 2], [3, 4]] == [[1, 2], [3, 4]]
  182. (Equating.array >>> Equating.array)(.int).equals([[1, 2], [3, 4]] , [[1, 2], [3, 4]])
  183. (Equating.array >>> Equating.array)(.int).equals([[1, 2], [3, 4]] , [[1, 2], [3, 4, 5]])
  184. (Equating.array >>> Equating.array)(stringCount)
  185. (Equating.array >>> Equating.array)(stringCount).equals([["Blob"], ["Blob Jr"]], [["Bolb"], ["Bolb Jr"]])
  186. (Equating.array >>> Equating.array)(stringCount).equals([["Blob"], ["Blob Jr"]], [["Bolb"], ["Bolb Esq"]])
  187. //extension (Int, Int) {
  188. // var sum: Int { return self.0 + self.1 }
  189. //}
  190. //extension (A, B): Equatable where A: Equatable, B: Equatable {
  191. // static func ==(lhs: (A, B), rhs: (A, B)) -> Bool {
  192. // return lhs.0 == rhs.0 && lhs.1 == rhs.1
  193. // }
  194. //}
  195. //extension Void: Equatable {
  196. // static func ==(lhs: Void, rhs: Void) -> Bool {
  197. // return true
  198. // }
  199. //}
  200. extension Equating where A == Void {
  201. static let void = Equating { _, _ in true }
  202. }
  203. Equating.array(of: .void).equals([(), ()], [(), ()])
  204. Equating.array(of: .void).equals([(), ()], [()])
  205. //[(), ()] == [()]
  206. extension Equating {
  207. static func tuple<B>(_ a: Equating<A>, _ b: Equating<B>) -> Equating<(A, B)> {
  208. return Equating<(A, B)> { lhs, rhs in
  209. a.equals(lhs.0, rhs.0) && b.equals(lhs.1, rhs.1)
  210. }
  211. }
  212. }
  213. Equating.tuple(.int, stringCount).equals((1, "Blob"), (1, "Bolb"))
  214. Equating.tuple(.int, stringCount).equals((1, "Blob"), (1, "Blob Jr"))
  215. Equating.tuple(.int, stringCount).equals((1, "Blob"), (2, "Bolb"))
  216. //extension (A) -> A: Combinable {
  217. // func combine(other f: @escaping (A) -> A) -> (A) -> A {
  218. // return { a in other(self(a)) }
  219. // }
  220. //}
  221. struct Endo<A>: Combinable {
  222. let call: (A) -> A
  223. func combine(with other: Endo) -> Endo {
  224. return Endo { a in other.call(self.call(a)) }
  225. }
  226. }
  227. extension Combining {
  228. static var endo: Combining<(A) -> A> {
  229. // return Combining<(A) -> A> { f, g in
  230. // { a in g(f(a)) }
  231. // }
  232. return Combining<(A) -> A>(combine: >>>)
  233. }
  234. }
  235. extension EmptyInitializing {
  236. static var identity: EmptyInitializing<(A) -> A> {
  237. return EmptyInitializing<(A) -> A> {
  238. { $0 }
  239. }
  240. }
  241. }
  242. let endos: [(Double) -> Double] = [
  243. { $0 + 1.0 },
  244. { $0 * $0 },
  245. sin,
  246. { $0 * 1000.0 }
  247. ]
  248. endos.reduce(EmptyInitializing.identity, Combining.endo)(3)
  249. //protocol Comparable: Equatable {
  250. // static func < (lhs: Self, rhs: Self) -> Bool
  251. //}
  252. struct Comparing<A> {
  253. let equating: Equating<A>
  254. let lessThan: (A, A) -> Bool
  255. func pullback<B>(_ f: @escaping (B) -> A) -> Comparing<B> {
  256. return Comparing<B>(
  257. equating: self.equating.pullback(f),
  258. lessThan: { lhs, rhs in
  259. self.lessThan(f(lhs), f(rhs))
  260. })
  261. }
  262. }
  263. let intAsc = Comparing(equating: .int, lessThan: <)
  264. let intDesc = Comparing(equating: .int, lessThan: >)
  265. struct User { let id: Int, name: String }
  266. intAsc.pullback(get(\User.id))
  267. intDesc.pullback(get(\User.id))
  268. intAsc.pullback(get(\User.name.count))
  269. extension Equating {
  270. var notEquals: (A, A) -> Bool {
  271. return { lhs, rhs in
  272. !self.equals(lhs, rhs)
  273. }
  274. }
  275. }
  276. public protocol Reusable {
  277. static var reuseIdentifier: String { get }
  278. }
  279. public extension Reusable {
  280. static var reuseIdentifier: String {
  281. return String(describing: self)
  282. }
  283. }
  284. class UserCell: UITableViewCell {}
  285. class EpisodeCell: UITableViewCell {}
  286. extension UserCell: Reusable {}
  287. extension EpisodeCell: Reusable {}
  288. UserCell.reuseIdentifier
  289. EpisodeCell.reuseIdentifier
  290. struct Reusing<A> {
  291. let reuseIdentifier: () -> String
  292. init(reuseIdentifier: @escaping () -> String = { String(describing: A.self) }) {
  293. self.reuseIdentifier = reuseIdentifier
  294. }
  295. }
  296. Reusing<UserCell>().reuseIdentifier()
  297. Reusing<EpisodeCell>().reuseIdentifier()
  298. //let collections: [Collection]
  299. //public protocol RawRepresentable {
  300. // associatedtype RawValue
  301. // public init?(rawValue: Self.RawValue)
  302. // public var rawValue: Self.RawValue { get }
  303. //}
  304. enum Directions: String {
  305. case down = "D"
  306. case left = "L"
  307. case right = "R"
  308. case up = "U"
  309. }
  310. Directions.down.rawValue
  311. Directions(rawValue: "D")
  312. Directions(rawValue: "X")
  313. struct RawRepresenting<A, RawValue> {
  314. let convert: (RawValue) -> A?
  315. let rawValue: (A) -> RawValue
  316. }
  317. extension RawRepresenting where A == Int, RawValue == String {
  318. static var stringToInt = RawRepresenting(
  319. convert: Int.init,
  320. rawValue: String.init(describing:)
  321. )
  322. }
  323. extension RawRepresenting where A: RawRepresentable, A.RawValue == RawValue {
  324. static var rawRepresentable: RawRepresenting {
  325. return RawRepresenting(
  326. convert: A.init(rawValue:),
  327. rawValue: { $0.rawValue }
  328. )
  329. }
  330. }
  331. RawRepresenting<Directions, String>.rawRepresentable