thoughtbot / runes Goto Github PK
View Code? Open in Web Editor NEWInfix operators for monadic functions in Swift
Home Page: https://thoughtbot.com/open-source
License: MIT License
Infix operators for monadic functions in Swift
Home Page: https://thoughtbot.com/open-source
License: MIT License
In the latest Swift 3 they've changed how precedence works for operators. I tried assigning arbitrary precedence to things to try to match the comments above each one, but that didn't work out well. I don't quite understand these custom operators enough to truly give them the precedence levels they desire.
Today I wanted to change this code to use operators:
// initial code
return index.map { $0 - 1 }.flatMap { viewControllerAtIndex($0) }
// what I thought would work
return return index <^> { $0 - 1 } >>- { self.viewControllerAtIndex($0) }
Turns out the second way gives you Binary operator '<^>' cannot be applied to operands of type 'Int?' and 'Int -> Int'
because the arguments are backwards for <^>
.
You'd have to do something like this to get the same same result:
return { self.viewControllerAtIndex($0) } -<< { $0 - 1 } <^> index
I'd like to propose adding the type signature for the first way I thought would work (last part of first code example). A similar thing was proposed for Haskell here but I'm unsure what the current status is.
Implementing this in Runes would look like adding this method:
public func <^><T, U>(a: T?, @noescape f: T -> U) -> U? {
return a.map(f)
}
I believe it would be backwards compatible since the type is flipped so it wouldn't conflict with anyone using it the current way.
I'm not super familiar with Haskell so perhaps this is the way it's done and I need to get used to it, I figured I'd propose this idea to get some discussion around it and hear others thoughts.
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 curried syntax?
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. pointfreeco/swift-snapshot-testing#201 .
What do you think?
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?
I'm trying to build with Carthage Argo
from the master
branch so it's compatible with Swift 3.0
, and the build fails.
I see that Argo
declares as a Carthage dependency Runes
on master
branch, so if I try to build Runes
from master
branch on Xcode8 beta 6, it fails due to some compilation errors.
Is there any way of getting Argo
and Runes
to work with Swift 3.0
I'm not aware of?
Thanks in advance for any help you can provide.
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.
A single example for each operator would do a lot
As of Xcode beta 3, Runes (swift-2.0) cannot compile, because 'T' has been renamed to 'Element' (as the compiler says in Array.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?
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.
Latest available through CocoaPods is 3.1.0.
Argo/Sources/Argo/Types/JSON.swift:89: '.flatMap { .success(.some($0)) }' seems to be the same as '.map { .some($0) }'.
Also, the documentation doesn't reflect the removal of '<|', '<|?' operators.
Thanks
We added @noescape
to <^>
for arrays in #58, but I suspect that we can do more of that. We should audit the existing code and add @noescape
annotations wherever possible. We should also look into using rethrows
where we can.
Hi ๐
I recently created Swift parser combinator library called https://github.com/tryswift/TryParsec (inspired by Argo โจ), and I'm planning to use Runes to keep same operator precedences as discussing in tryswift/TryParsec#11.
Specifically, I want Runes to have following declarations:
/// Haskell `infixl 3`.
/// - Note: typelift/Operadics use `precedence 120` for `infixr 2` and `precedence 130` for `infixl 4`.
infix operator <|> { associativity left precedence 125 }
/// Haskell `infixl 4`.
infix operator <* { associativity left precedence 140 }
/// Haskell `infixl 4`.
infix operator *> { associativity left precedence 140 }
I also found typelift/Operadics useful, but infix operator <|>
was still missing.
Since Runes seems more de-facto library, I would like to ask what will be the good solution.
Thanks!
I was trying to run my iOS app on my iPhone. Project compiled nicely. But when app starts, XCode console showed:
dyld: Library not loaded: @rpath/Runes.framework/Runes
Referenced from: /private/var/mobile/Containers/Bundle/Application/CC8759F5-A501-400C-93A8-DCEE3BFE4770/XXX.app/XXX
Reason: Incompatible library version: XXX requires version 2.0.0 or later, but Runes provides version 1.0.0
I use Cocoapods and my Podfile looks like:
platform :ios, '8.0'
use_frameworks!
pod 'SnapKit', '~> 0.12.0'
pod 'Alamofire', '~> 1.2'
pod 'SwiftTask', '~> 3.3'
pod 'Argo'
pod 'Async', :git => 'https://github.com/duemunk/Async.git', :commit => '9e64046b767fe11010891f5b7fe2aed613a6ee55'
pod 'TapLabel', '0.0.3'
pod 'RealmSwift'
pod 'Kingfisher', '~> 1.4'
What should I do? Everything works fine on simulators.
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?
I'd love to be able to use #56 in my project. No pressure though! ๐
This library is great. Thank you for putting it together.
I'd like to suggest adding some default implementations for functions themselves. I'd be willing to contribute these 4 operators that I see in other languages (F# for example, https://theburningmonk.com/2011/09/fsharp-pipe-forward-and-pipe-backward/):
<< func compose backward f << g = g(f) result is a new function
>> func compose forward f >> g. = f(g) result is a new function
<| backward pipe f <| g <| x = f(g(x)) output is the application of both functions to x
|> forward pipe. x |> f |> g = g(f(x)) output is the application of both functions to x
Please tell me if you are interested.
It'd be nice to add some Jazzy docs to this project, and host them using github pages. We should do that as a part of the release process (see #91)
podspec still has Source
as the directory name, needs to be Sources
.
Hi!
Super minor thing but the case studies link at the bottom of the project readme returns "Page not found". It seems this is the case for other Thoughtbot iOS Github projects as well.
Thanks for the great work and all the awesome open source projects shared!
In Array.swift
I was just trying to update to the latest release (4.0.1) using Cocoapods and saw that this version wasn't published there yet.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.