diff --git a/Overture.playground/Contents.swift b/Overture.playground/Pages/Basics.xcplaygroundpage/Contents.swift similarity index 100% rename from Overture.playground/Contents.swift rename to Overture.playground/Pages/Basics.xcplaygroundpage/Contents.swift diff --git a/Overture.playground/Pages/UIKit Setters.xcplaygroundpage/Contents.swift b/Overture.playground/Pages/UIKit Setters.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..cd6d10f --- /dev/null +++ b/Overture.playground/Pages/UIKit Setters.xcplaygroundpage/Contents.swift @@ -0,0 +1,70 @@ +import Overture +import UIKit + +// Base Styles + +let autolayoutStyle = mut(\UIView.translatesAutoresizingMaskIntoConstraints, false) + +let roundedStyle = concat( + mut(\UIView.clipsToBounds, true), + mut(\.layer.cornerRadius, 6) +) + +func borderStyle(color: UIColor, width: CGFloat) -> (UIView) -> Void { + return concat( + mut(\UIView.layer.borderColor, color.cgColor), + mut(\.layer.borderWidth, width) + ) +} + +func buttonFont(_ font: UIFont) -> (UIButton) -> Void { + return { $0.titleLabel?.font = font } +} + +func buttonTitle(_ title: String, for state: UIControlState = .normal) -> (UIButton) -> Void { + return { $0.setTitle(title, for: state) } +} + +func buttonTitleColor(_ color: UIColor, for state: UIControlState = .normal) -> (UIButton) -> Void { + return { $0.setTitleColor(color, for: state) } +} + +// App Styles + +let baseButtonStyle: (UIButton) -> Void = concat( + mut(\.contentEdgeInsets, .init(top: 12, left: 16, bottom: 12, right: 16)), + buttonFont(.systemFont(ofSize: 16)) +) + +let roundButtonStyle = concat( + baseButtonStyle, + roundedStyle +) + +let filledButtonStyle = concat( + roundButtonStyle, + mut(\.backgroundColor, .black), + mut(\.tintColor, .white) +) + +let borderButtonStyle = concat( + roundButtonStyle, + borderStyle(color: .black, width: 2), + buttonTitleColor(.black) +) + +let nextButton = with( + UIButton(), + concat( + filledButtonStyle, + buttonTitle("Next") + ) +) + +let cancelButton = with( + UIButton(), + concat( + borderButtonStyle, + buttonTitle("Cancel") + ) +) diff --git a/Overture.playground/Pages/URLRequest Setters - Immutable.xcplaygroundpage/Contents.swift b/Overture.playground/Pages/URLRequest Setters - Immutable.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..14539db --- /dev/null +++ b/Overture.playground/Pages/URLRequest Setters - Immutable.xcplaygroundpage/Contents.swift @@ -0,0 +1,29 @@ +import Foundation +import Overture + +let guaranteeHeaders = over(\URLRequest.allHTTPHeaderFields) { $0 ?? [:] } + +let setHeader = { name, value in + concat( + guaranteeHeaders, + set(compose(prop(\.allHTTPHeaderFields), map, prop(\.[name])), value) + ) +} + +let postJson = concat( + set(\.httpMethod, "POST"), + setHeader("Content-Type", "application/json; charset=utf-8") +) + +let gitHubAccept = setHeader("Accept", "application/vnd.github.v3+json") + +let attachAuthorization = { token in setHeader("Authorization", "Token " + token) } + +let request = with( + URLRequest(url: URL(string: "https://www.pointfree.co/hello")!), + concat( + attachAuthorization("deadbeef"), + gitHubAccept, + postJson + ) +) diff --git a/Overture.playground/Pages/URLRequest Setters - Mutable.xcplaygroundpage/Contents.swift b/Overture.playground/Pages/URLRequest Setters - Mutable.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..88918d0 --- /dev/null +++ b/Overture.playground/Pages/URLRequest Setters - Mutable.xcplaygroundpage/Contents.swift @@ -0,0 +1,26 @@ +import Foundation +import Overture + +let guaranteeHeaders = mver(\URLRequest.allHTTPHeaderFields) { $0 = $0 ?? [:] } + +let setHeader = { name, value in + concat(guaranteeHeaders) { $0.allHTTPHeaderFields?[name] = value } +} + +let postJson = concat( + mut(\.httpMethod, "POST"), + setHeader("Content-Type", "application/json; charset=utf-8") +) + +let gitHubAccept = setHeader("Accept", "application/vnd.github.v3+json") + +let attachAuthorization = { token in setHeader("Authorization", "Token " + token) } + +let request = with( + URLRequest(url: URL(string: "https://www.pointfree.co/hello")!), + concat( + attachAuthorization("deadbeef"), + gitHubAccept, + postJson + ) +) diff --git a/Overture.playground/contents.xcplayground b/Overture.playground/contents.xcplayground index faac376..e24a9d8 100644 --- a/Overture.playground/contents.xcplayground +++ b/Overture.playground/contents.xcplayground @@ -1,2 +1,9 @@ - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/Overture.xcodeproj/project.pbxproj b/Overture.xcodeproj/project.pbxproj index cadb440..b2f396b 100644 --- a/Overture.xcodeproj/project.pbxproj +++ b/Overture.xcodeproj/project.pbxproj @@ -9,11 +9,11 @@ /* Begin PBXAggregateTarget section */ "Overture::OverturePackageTests::ProductTarget" /* OverturePackageTests */ = { isa = PBXAggregateTarget; - buildConfigurationList = OBJ_62 /* Build configuration list for PBXAggregateTarget "OverturePackageTests" */; + buildConfigurationList = OBJ_66 /* Build configuration list for PBXAggregateTarget "OverturePackageTests" */; buildPhases = ( ); dependencies = ( - OBJ_65 /* PBXTargetDependency */, + OBJ_69 /* PBXTargetDependency */, ); name = OverturePackageTests; productName = OverturePackageTests; @@ -21,39 +21,40 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - OBJ_42 /* Chain.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* Chain.swift */; }; - OBJ_43 /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* Compose.swift */; }; - OBJ_44 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Concat.swift */; }; - OBJ_45 /* Curry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* Curry.swift */; }; - OBJ_46 /* Flip.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Flip.swift */; }; - OBJ_47 /* KeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* KeyPath.swift */; }; - OBJ_48 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* Optional.swift */; }; - OBJ_49 /* Pipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* Pipe.swift */; }; - OBJ_50 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* Sequence.swift */; }; - OBJ_51 /* Uncurry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* Uncurry.swift */; }; - OBJ_52 /* With.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* With.swift */; }; - OBJ_53 /* Zurry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* Zurry.swift */; }; - OBJ_60 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; - OBJ_71 /* ChainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* ChainTests.swift */; }; - OBJ_72 /* ComposeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* ComposeTests.swift */; }; - OBJ_73 /* ConcatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* ConcatTests.swift */; }; - OBJ_74 /* CurryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* CurryTests.swift */; }; - OBJ_75 /* FlipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* FlipTests.swift */; }; - OBJ_76 /* PipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* PipeTests.swift */; }; - OBJ_77 /* UncurryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* UncurryTests.swift */; }; - OBJ_78 /* WithTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* WithTests.swift */; }; - OBJ_80 /* Overture.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Overture::Overture::Product" /* Overture.framework */; }; + OBJ_44 /* Chain.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* Chain.swift */; }; + OBJ_45 /* Compose.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* Compose.swift */; }; + OBJ_46 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Concat.swift */; }; + OBJ_47 /* Curry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* Curry.swift */; }; + OBJ_48 /* Flip.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* Flip.swift */; }; + OBJ_50 /* KeyPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* KeyPath.swift */; }; + OBJ_51 /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* Optional.swift */; }; + OBJ_52 /* Pipe.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* Pipe.swift */; }; + OBJ_53 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* Sequence.swift */; }; + OBJ_54 /* Setters.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* Setters.swift */; }; + OBJ_55 /* Uncurry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* Uncurry.swift */; }; + OBJ_56 /* With.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* With.swift */; }; + OBJ_57 /* Zurry.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* Zurry.swift */; }; + OBJ_64 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; + OBJ_75 /* ChainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* ChainTests.swift */; }; + OBJ_76 /* ComposeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* ComposeTests.swift */; }; + OBJ_77 /* ConcatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_29 /* ConcatTests.swift */; }; + OBJ_78 /* CurryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_30 /* CurryTests.swift */; }; + OBJ_79 /* FlipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_31 /* FlipTests.swift */; }; + OBJ_80 /* PipeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_32 /* PipeTests.swift */; }; + OBJ_81 /* UncurryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_33 /* UncurryTests.swift */; }; + OBJ_82 /* WithTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_34 /* WithTests.swift */; }; + OBJ_84 /* Overture.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "Overture::Overture::Product" /* Overture.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - DCF8CF9A208B90CC00E79107 /* PBXContainerItemProxy */ = { + DCA3A77020939AB4000903A3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = OBJ_1 /* Project object */; proxyType = 1; remoteGlobalIDString = "Overture::Overture"; remoteInfo = Overture; }; - DCF8CF9B208B90CC00E79107 /* PBXContainerItemProxy */ = { + DCA3A77120939AB4000903A3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = OBJ_1 /* Project object */; proxyType = 1; @@ -68,22 +69,23 @@ OBJ_13 /* Concat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Concat.swift; sourceTree = ""; }; OBJ_14 /* Curry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Curry.swift; sourceTree = ""; }; OBJ_15 /* Flip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flip.swift; sourceTree = ""; }; - OBJ_16 /* KeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPath.swift; sourceTree = ""; }; - OBJ_17 /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; - OBJ_18 /* Pipe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pipe.swift; sourceTree = ""; }; - OBJ_19 /* Sequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = ""; }; - OBJ_20 /* Uncurry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Uncurry.swift; sourceTree = ""; }; - OBJ_21 /* With.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = With.swift; sourceTree = ""; }; - OBJ_22 /* Zurry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zurry.swift; sourceTree = ""; }; - OBJ_25 /* ChainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainTests.swift; sourceTree = ""; }; - OBJ_26 /* ComposeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTests.swift; sourceTree = ""; }; - OBJ_27 /* ConcatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcatTests.swift; sourceTree = ""; }; - OBJ_28 /* CurryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurryTests.swift; sourceTree = ""; }; - OBJ_29 /* FlipTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlipTests.swift; sourceTree = ""; }; - OBJ_30 /* PipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipeTests.swift; sourceTree = ""; }; - OBJ_31 /* UncurryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UncurryTests.swift; sourceTree = ""; }; - OBJ_32 /* WithTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WithTests.swift; sourceTree = ""; }; - OBJ_33 /* Overture.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = Overture.xcworkspace; sourceTree = SOURCE_ROOT; }; + OBJ_17 /* KeyPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPath.swift; sourceTree = ""; }; + OBJ_18 /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; + OBJ_19 /* Pipe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pipe.swift; sourceTree = ""; }; + OBJ_20 /* Sequence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sequence.swift; sourceTree = ""; }; + OBJ_21 /* Setters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Setters.swift; sourceTree = ""; }; + OBJ_22 /* Uncurry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Uncurry.swift; sourceTree = ""; }; + OBJ_23 /* With.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = With.swift; sourceTree = ""; }; + OBJ_24 /* Zurry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Zurry.swift; sourceTree = ""; }; + OBJ_27 /* ChainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainTests.swift; sourceTree = ""; }; + OBJ_28 /* ComposeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeTests.swift; sourceTree = ""; }; + OBJ_29 /* ConcatTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConcatTests.swift; sourceTree = ""; }; + OBJ_30 /* CurryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurryTests.swift; sourceTree = ""; }; + OBJ_31 /* FlipTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlipTests.swift; sourceTree = ""; }; + OBJ_32 /* PipeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PipeTests.swift; sourceTree = ""; }; + OBJ_33 /* UncurryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UncurryTests.swift; sourceTree = ""; }; + OBJ_34 /* WithTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WithTests.swift; sourceTree = ""; }; + OBJ_35 /* Overture.xcworkspace */ = {isa = PBXFileReference; lastKnownFileType = wrapper.workspace; path = Overture.xcworkspace; sourceTree = SOURCE_ROOT; }; OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; OBJ_8 /* Development.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Development.xcconfig; sourceTree = ""; }; "Overture::Overture::Product" /* Overture.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Overture.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -91,18 +93,18 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - OBJ_54 /* Frameworks */ = { + OBJ_58 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 0; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - OBJ_79 /* Frameworks */ = { + OBJ_83 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 0; files = ( - OBJ_80 /* Overture.framework in Frameworks */, + OBJ_84 /* Overture.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -117,43 +119,44 @@ OBJ_13 /* Concat.swift */, OBJ_14 /* Curry.swift */, OBJ_15 /* Flip.swift */, - OBJ_16 /* KeyPath.swift */, - OBJ_17 /* Optional.swift */, - OBJ_18 /* Pipe.swift */, - OBJ_19 /* Sequence.swift */, - OBJ_20 /* Uncurry.swift */, - OBJ_21 /* With.swift */, - OBJ_22 /* Zurry.swift */, + OBJ_17 /* KeyPath.swift */, + OBJ_18 /* Optional.swift */, + OBJ_19 /* Pipe.swift */, + OBJ_20 /* Sequence.swift */, + OBJ_21 /* Setters.swift */, + OBJ_22 /* Uncurry.swift */, + OBJ_23 /* With.swift */, + OBJ_24 /* Zurry.swift */, ); name = Overture; path = Sources/Overture; sourceTree = SOURCE_ROOT; }; - OBJ_23 /* Tests */ = { + OBJ_25 /* Tests */ = { isa = PBXGroup; children = ( - OBJ_24 /* OvertureTests */, + OBJ_26 /* OvertureTests */, ); name = Tests; sourceTree = SOURCE_ROOT; }; - OBJ_24 /* OvertureTests */ = { + OBJ_26 /* OvertureTests */ = { isa = PBXGroup; children = ( - OBJ_25 /* ChainTests.swift */, - OBJ_26 /* ComposeTests.swift */, - OBJ_27 /* ConcatTests.swift */, - OBJ_28 /* CurryTests.swift */, - OBJ_29 /* FlipTests.swift */, - OBJ_30 /* PipeTests.swift */, - OBJ_31 /* UncurryTests.swift */, - OBJ_32 /* WithTests.swift */, + OBJ_27 /* ChainTests.swift */, + OBJ_28 /* ComposeTests.swift */, + OBJ_29 /* ConcatTests.swift */, + OBJ_30 /* CurryTests.swift */, + OBJ_31 /* FlipTests.swift */, + OBJ_32 /* PipeTests.swift */, + OBJ_33 /* UncurryTests.swift */, + OBJ_34 /* WithTests.swift */, ); name = OvertureTests; path = Tests/OvertureTests; sourceTree = SOURCE_ROOT; }; - OBJ_34 /* Products */ = { + OBJ_36 /* Products */ = { isa = PBXGroup; children = ( "Overture::OvertureTests::Product" /* OvertureTests.xctest */, @@ -162,17 +165,16 @@ name = Products; sourceTree = BUILT_PRODUCTS_DIR; }; - OBJ_5 /* */ = { + OBJ_5 = { isa = PBXGroup; children = ( OBJ_6 /* Package.swift */, OBJ_7 /* Configs */, OBJ_9 /* Sources */, - OBJ_23 /* Tests */, - OBJ_33 /* Overture.xcworkspace */, - OBJ_34 /* Products */, + OBJ_25 /* Tests */, + OBJ_35 /* Overture.xcworkspace */, + OBJ_36 /* Products */, ); - name = ""; sourceTree = ""; }; OBJ_7 /* Configs */ = { @@ -196,10 +198,10 @@ /* Begin PBXNativeTarget section */ "Overture::Overture" /* Overture */ = { isa = PBXNativeTarget; - buildConfigurationList = OBJ_38 /* Build configuration list for PBXNativeTarget "Overture" */; + buildConfigurationList = OBJ_40 /* Build configuration list for PBXNativeTarget "Overture" */; buildPhases = ( - OBJ_41 /* Sources */, - OBJ_54 /* Frameworks */, + OBJ_43 /* Sources */, + OBJ_58 /* Frameworks */, ); buildRules = ( ); @@ -212,15 +214,15 @@ }; "Overture::OvertureTests" /* OvertureTests */ = { isa = PBXNativeTarget; - buildConfigurationList = OBJ_67 /* Build configuration list for PBXNativeTarget "OvertureTests" */; + buildConfigurationList = OBJ_71 /* Build configuration list for PBXNativeTarget "OvertureTests" */; buildPhases = ( - OBJ_70 /* Sources */, - OBJ_79 /* Frameworks */, + OBJ_74 /* Sources */, + OBJ_83 /* Frameworks */, ); buildRules = ( ); dependencies = ( - OBJ_81 /* PBXTargetDependency */, + OBJ_85 /* PBXTargetDependency */, ); name = OvertureTests; productName = OvertureTests; @@ -229,9 +231,9 @@ }; "Overture::SwiftPMPackageDescription" /* OverturePackageDescription */ = { isa = PBXNativeTarget; - buildConfigurationList = OBJ_56 /* Build configuration list for PBXNativeTarget "OverturePackageDescription" */; + buildConfigurationList = OBJ_60 /* Build configuration list for PBXNativeTarget "OverturePackageDescription" */; buildPhases = ( - OBJ_59 /* Sources */, + OBJ_63 /* Sources */, ); buildRules = ( ); @@ -256,8 +258,8 @@ knownRegions = ( en, ); - mainGroup = OBJ_5 /* */; - productRefGroup = OBJ_34 /* Products */; + mainGroup = OBJ_5; + productRefGroup = OBJ_36 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( @@ -270,60 +272,61 @@ /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ - OBJ_41 /* Sources */ = { + OBJ_43 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 0; files = ( - OBJ_42 /* Chain.swift in Sources */, - OBJ_43 /* Compose.swift in Sources */, - OBJ_44 /* Concat.swift in Sources */, - OBJ_45 /* Curry.swift in Sources */, - OBJ_46 /* Flip.swift in Sources */, - OBJ_47 /* KeyPath.swift in Sources */, - OBJ_48 /* Optional.swift in Sources */, - OBJ_49 /* Pipe.swift in Sources */, - OBJ_50 /* Sequence.swift in Sources */, - OBJ_51 /* Uncurry.swift in Sources */, - OBJ_52 /* With.swift in Sources */, - OBJ_53 /* Zurry.swift in Sources */, + OBJ_44 /* Chain.swift in Sources */, + OBJ_45 /* Compose.swift in Sources */, + OBJ_46 /* Concat.swift in Sources */, + OBJ_47 /* Curry.swift in Sources */, + OBJ_48 /* Flip.swift in Sources */, + OBJ_50 /* KeyPath.swift in Sources */, + OBJ_51 /* Optional.swift in Sources */, + OBJ_52 /* Pipe.swift in Sources */, + OBJ_53 /* Sequence.swift in Sources */, + OBJ_54 /* Setters.swift in Sources */, + OBJ_55 /* Uncurry.swift in Sources */, + OBJ_56 /* With.swift in Sources */, + OBJ_57 /* Zurry.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - OBJ_59 /* Sources */ = { + OBJ_63 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 0; files = ( - OBJ_60 /* Package.swift in Sources */, + OBJ_64 /* Package.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - OBJ_70 /* Sources */ = { + OBJ_74 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 0; files = ( - OBJ_71 /* ChainTests.swift in Sources */, - OBJ_72 /* ComposeTests.swift in Sources */, - OBJ_73 /* ConcatTests.swift in Sources */, - OBJ_74 /* CurryTests.swift in Sources */, - OBJ_75 /* FlipTests.swift in Sources */, - OBJ_76 /* PipeTests.swift in Sources */, - OBJ_77 /* UncurryTests.swift in Sources */, - OBJ_78 /* WithTests.swift in Sources */, + OBJ_75 /* ChainTests.swift in Sources */, + OBJ_76 /* ComposeTests.swift in Sources */, + OBJ_77 /* ConcatTests.swift in Sources */, + OBJ_78 /* CurryTests.swift in Sources */, + OBJ_79 /* FlipTests.swift in Sources */, + OBJ_80 /* PipeTests.swift in Sources */, + OBJ_81 /* UncurryTests.swift in Sources */, + OBJ_82 /* WithTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - OBJ_65 /* PBXTargetDependency */ = { + OBJ_69 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = "Overture::OvertureTests" /* OvertureTests */; - targetProxy = DCF8CF9B208B90CC00E79107 /* PBXContainerItemProxy */; + targetProxy = DCA3A77120939AB4000903A3 /* PBXContainerItemProxy */; }; - OBJ_81 /* PBXTargetDependency */ = { + OBJ_85 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = "Overture::Overture" /* Overture */; - targetProxy = DCF8CF9A208B90CC00E79107 /* PBXContainerItemProxy */; + targetProxy = DCA3A77020939AB4000903A3 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -350,7 +353,27 @@ }; name = Debug; }; - OBJ_39 /* Debug */ = { + OBJ_4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_OPTIMIZATION_LEVEL = s; + MACOSX_DEPLOYMENT_TARGET = 10.10; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + USE_HEADERMAP = NO; + }; + name = Release; + }; + OBJ_41 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = OBJ_8 /* Development.xcconfig */; buildSettings = { @@ -374,27 +397,7 @@ }; name = Debug; }; - OBJ_4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_ENABLE_OBJC_ARC = YES; - COMBINE_HIDPI_IMAGES = YES; - COPY_PHASE_STRIP = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_OPTIMIZATION_LEVEL = s; - MACOSX_DEPLOYMENT_TARGET = 10.10; - OTHER_SWIFT_FLAGS = "-DXcode"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - USE_HEADERMAP = NO; - }; - name = Release; - }; - OBJ_40 /* Release */ = { + OBJ_42 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = OBJ_8 /* Development.xcconfig */; buildSettings = { @@ -418,7 +421,7 @@ }; name = Release; }; - OBJ_57 /* Debug */ = { + OBJ_61 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { LD = /usr/bin/true; @@ -427,7 +430,7 @@ }; name = Debug; }; - OBJ_58 /* Release */ = { + OBJ_62 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { LD = /usr/bin/true; @@ -436,19 +439,19 @@ }; name = Release; }; - OBJ_63 /* Debug */ = { + OBJ_67 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Debug; }; - OBJ_64 /* Release */ = { + OBJ_68 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { }; name = Release; }; - OBJ_68 /* Debug */ = { + OBJ_72 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = OBJ_8 /* Development.xcconfig */; buildSettings = { @@ -468,7 +471,7 @@ }; name = Debug; }; - OBJ_69 /* Release */ = { + OBJ_73 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = OBJ_8 /* Development.xcconfig */; buildSettings = { @@ -500,38 +503,38 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - OBJ_38 /* Build configuration list for PBXNativeTarget "Overture" */ = { + OBJ_40 /* Build configuration list for PBXNativeTarget "Overture" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJ_39 /* Debug */, - OBJ_40 /* Release */, + OBJ_41 /* Debug */, + OBJ_42 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - OBJ_56 /* Build configuration list for PBXNativeTarget "OverturePackageDescription" */ = { + OBJ_60 /* Build configuration list for PBXNativeTarget "OverturePackageDescription" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJ_57 /* Debug */, - OBJ_58 /* Release */, + OBJ_61 /* Debug */, + OBJ_62 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - OBJ_62 /* Build configuration list for PBXAggregateTarget "OverturePackageTests" */ = { + OBJ_66 /* Build configuration list for PBXAggregateTarget "OverturePackageTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJ_63 /* Debug */, - OBJ_64 /* Release */, + OBJ_67 /* Debug */, + OBJ_68 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - OBJ_67 /* Build configuration list for PBXNativeTarget "OvertureTests" */ = { + OBJ_71 /* Build configuration list for PBXNativeTarget "OvertureTests" */ = { isa = XCConfigurationList; buildConfigurations = ( - OBJ_68 /* Debug */, - OBJ_69 /* Release */, + OBJ_72 /* Debug */, + OBJ_73 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/README.md b/README.md index ac9c22a..328e0f4 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,44 @@ with(User(name: "blob", age: 1), concat( // User(name: "Blob", age: 2) ``` +### `over` and `set` + +The `over` and `set` functions produce `(Root) -> Root` transform functions that work on a `Value` in a structure given a key path (or [setter function](https://www.pointfree.co/episodes/ep7-setters-and-key-paths)). + +The `over` function takes a `(Value) -> Value` transform function to modify an existing value. + +``` swift +let celebrateBirthday = over(\User.age, incr) +// (User) -> User +``` + +The `set` function replaces an existing value with a brand new one. + +```swift +with(user, set(\.name, "Blob")) +``` + +### `mprop`, `mver`, and `mut` + +The `mprop`, `mver` and `mut` functions are _mutable_ variants of `prop`, `over` and `set`. + +```swift +let guaranteeHeaders = mver(\URLRequest.allHTTPHeaderFields) { $0 = $0 ?? [:] } + +let setHeader = { name, value in + concat( + guaranteeHeaders, + { $0.allHTTPHeaderFields?[name] = value } + ) +} + +let request = with(URLRequest(url: url), concat( + mut(\.httpMethod, "POST"), + setHeader("Authorization", "Token " + token), + setHeader("Content-Type", "application/json; charset=utf-8") +)) +``` + ## FAQ - **Should I be worried about polluting the global namespace with free functions?** diff --git a/Sources/Overture/Concat.swift b/Sources/Overture/Concat.swift index a060022..1e40bfa 100644 --- a/Sources/Overture/Concat.swift +++ b/Sources/Overture/Concat.swift @@ -1,4 +1,20 @@ +/// Composes an array of functions that take and return the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: [(A) -> A] + ) + -> (A) -> A { + + return { (a: A) -> A in + fs.reduce(a) { a, f in f(a) } + } +} + /// Forward composition of functions that take and return the same type. /// /// - Parameters: @@ -13,8 +29,22 @@ public func concat( ) -> (A) -> A { - return { (a: A) -> A in - fz(fs.reduce(a) { a, f in f(a) }) + return concat(fs + [fz]) +} + +/// Composes an array of throwing functions that take and return the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: [(A) throws -> A] + ) + -> (A) throws -> A { + + return { (a: A) throws -> A in + try fs.reduce(a) { a, f in try f(a) } } } @@ -32,32 +62,26 @@ public func concat( ) -> (A) throws -> A { - return { (a: A) throws -> A in - try fz(fs.reduce(a) { a, f in try f(a) }) - } + return concat(fs + [fz]) } +/// Composes an array of mutable functions that mutate the same type. /// /// - Parameters: /// - fs: Zero or more functions to apply in order. -/// - fz: A final, optional, terminating function for trailing closure syntax. -/// - a: The argument to the final function. /// - Returns: A new function that applies every function given as input in order. /// - Note: This function is commonly seen in operator form as `<>`. public func concat( - _ fs: ((inout A) -> Void)..., - and fz: @escaping (_ a: inout A) -> Void = { _ in } + _ fs: [(inout A) -> Void] ) -> (inout A) -> Void { return { (a: inout A) -> Void in fs.forEach { f in f(&a) } - fz(&a) } } - -/// Forward, mutable value composition of throwing functions that take and return the same type. +/// Forward composition of mutable functions that mutate the same type. /// /// - Parameters: /// - fs: Zero or more functions to apply in order. @@ -66,18 +90,31 @@ public func concat( /// - Returns: A new function that applies every function given as input in order. /// - Note: This function is commonly seen in operator form as `<>`. public func concat( - _ fs: ((inout A) throws -> Void)..., - and fz: @escaping (_ a: inout A) throws -> Void = { _ in } + _ fs: ((inout A) -> Void)..., + and fz: @escaping (_ a: inout A) -> Void = { _ in } + ) + -> (inout A) -> Void { + + return concat(fs + [fz]) +} + +/// Composes an array of mutable, throwing functions that mutate the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: [(inout A) throws -> Void] ) -> (inout A) throws -> Void { return { (a: inout A) throws -> Void in try fs.forEach { f in try f(&a) } - try fz(&a) } } -/// Forward, mutable reference composition of functions that take and return the same type. +/// Forward composition of mutable, throwing functions that mutate the same type. /// /// - Parameters: /// - fs: Zero or more functions to apply in order. @@ -85,34 +122,73 @@ public func concat( /// - a: The argument to the final function. /// - Returns: A new function that applies every function given as input in order. /// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: ((inout A) throws -> Void)..., + and fz: @escaping (_ a: inout A) throws -> Void = { _ in } + ) + -> (inout A) throws -> Void { + + return concat(fs + [fz]) +} + +/// Composes an array of reference-mutable functions that mutate the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. public func concat( - _ fs: ((A) -> Void)..., - and fz: @escaping (_ a: A) -> Void = { _ in } + _ fs: [(A) -> Void] ) -> (A) -> Void { return { (a: A) -> Void in fs.forEach { f in f(a) } - fz(a) } } -/// Forward, mutable reference composition of throwing functions that take and return the same type. +/// Forward composition of reference-mutable functions that mutate the same type. /// /// - Parameters: /// - fs: Zero or more functions to apply in order. -/// - fz: A final, optional, terminating function for trailing closure syntax. -/// - a: The argument to the final function. /// - Returns: A new function that applies every function given as input in order. /// - Note: This function is commonly seen in operator form as `<>`. public func concat( - _ fs: ((A) throws -> Void)..., - and fz: @escaping (_ a: A) throws -> Void = { _ in } + _ fs: ((A) -> Void)..., + and fz: @escaping (_ a: A) -> Void = { _ in } + ) + -> (A) -> Void { + + return concat(fs + [fz]) +} + +/// Composes an array of reference-mutable, throwing functions that mutate the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: [(A) throws -> Void] ) -> (A) throws -> Void { return { (a: A) throws -> Void in try fs.forEach { f in try f(a) } - try fz(a) } } + +/// Forward composition of reference-mutable, throwing functions that mutate the same type. +/// +/// - Parameters: +/// - fs: Zero or more functions to apply in order. +/// - Returns: A new function that applies every function given as input in order. +/// - Note: This function is commonly seen in operator form as `<>`. +public func concat( + _ fs: ((A) throws -> Void)..., + and fz: @escaping (_ a: A) throws -> Void = { _ in } + ) + -> (A) throws -> Void { + + return concat(fs + [fz]) +} diff --git a/Sources/Overture/KeyPath.swift b/Sources/Overture/KeyPath.swift index cbdf163..ea8da8e 100644 --- a/Sources/Overture/KeyPath.swift +++ b/Sources/Overture/KeyPath.swift @@ -10,22 +10,179 @@ public func get(_ keyPath: KeyPath) -> (Root) -> Value return { root in root[keyPath: keyPath] } } -/// Produces a setter function for a given key path. Useful for composing property updates with functions. -/// -/// prop(\URLRequest.url) -/// // ((URL?) -> URL?) -> (URLRequest) -> URLRequest +/// Produces an immutable setter function for a given key path. Useful for composing property changes. /// /// - Parameter keyPath: A key path. /// - Returns: A setter function. -public func prop(_ keyPath: WritableKeyPath) +public func prop( + _ keyPath: WritableKeyPath + ) -> (@escaping (Value) -> Value) -> (Root) -> Root { return { update in { root in var copy = root - copy[keyPath: keyPath] = update(root[keyPath: keyPath]) + copy[keyPath: keyPath] = update(copy[keyPath: keyPath]) return copy } } } + +/// Produces an immutable setter function for a given key path and update function. +/// +/// - Parameters +/// - keyPath: A key path. +/// - update: An update function. +/// - Returns: A setter function. +public func over( + _ keyPath: WritableKeyPath, + _ update: @escaping (Value) -> Value + ) + -> (Root) -> Root { + + return prop(keyPath)(update) +} + +/// Produces an immutable setter function for a given key path and constant value. +/// +/// - Parameters: +/// - keyPath: A key path. +/// - value: A new value. +/// - Returns: A setter function. +public func set( + _ keyPath: WritableKeyPath, + _ value: Value + ) + -> (Root) -> Root { + + return over(keyPath) { _ in value } +} + +// MARK: - Mutation + +/// Produces an in-place setter function for a given key path. Useful for composing value property changes efficiently. +/// +/// - Parameter keyPath: A writable key path. +/// - Returns: A mutable setter function. +public func mprop( + _ keyPath: WritableKeyPath + ) + -> (@escaping (inout Value) -> Void) + -> (inout Root) -> Void { + + return { update in + { root in + update(&root[keyPath: keyPath]) + } + } +} + +/// Uncurried `mver`. Takes a key path and update function all at once. +/// +/// - Parameters: +/// - keyPath: A writable key path. +/// - update: An update function for a given value. +/// - Returns: A value-mutable setter function. +public func mver( + _ keyPath: WritableKeyPath, + _ update: @escaping (inout Value) -> Void + ) + -> (inout Root) -> Void { + + return mprop(keyPath)(update) +} + +/// Produces a reference-mutable setter function for a given key path to a reference. Useful for composing reference property changes efficiently. +/// +/// - Parameter keyPath: A reference-writable key path. +/// - Returns: A reference-mutable setter function. +public func mprop( + _ keyPath: ReferenceWritableKeyPath + ) + -> (@escaping (Value) -> Void) + -> (Root) -> Void { + + return { update in + { root in + update(root[keyPath: keyPath]) + } + } +} + +/// Uncurried `mver`. Takes a key path and update function all at once. +/// +/// - Parameters: +/// - keyPath: A reference-writable key path. +/// - update: An update function for a given value. +/// - Returns: A reference-mutable setter function. +public func mver( + _ keyPath: ReferenceWritableKeyPath, + _ update: @escaping (Value) -> Void + ) + -> (Root) -> Void { + + return mprop(keyPath)(update) +} + +/// Produces an reference-mutable setter function for a given key path to a value. Useful for composing reference property changes efficiently. +/// +/// - Parameter keyPath: A key path. +/// - Returns: A setter function. +public func mprop( + _ keyPath: ReferenceWritableKeyPath + ) + -> (@escaping (inout Value) -> Void) + -> (Root) -> Void { + + return { update in + { root in + update(&root[keyPath: keyPath]) + } + } +} + +/// Uncurried `mver`. Takes a key path and update function all at once. +/// +/// - Parameters: +/// - keyPath: A reference-writable key path. +/// - update: An update function for a given value. +/// - Returns: A reference-mutable setter function. +public func mver( + _ keyPath: ReferenceWritableKeyPath, + _ update: @escaping (inout Value) -> Void + ) + -> (Root) -> Void { + + return mprop(keyPath)(update) +} + +/// Produces a value-mutable setter function for a given key path and new value. +/// +/// - Parameters: +/// - keyPath: A writable key path. +/// - value: A new value. +/// - Returns: A value-mutable setter function. +public func mut( + _ keyPath: WritableKeyPath, + _ value: Value + ) + -> (inout Root) -> Void { + + return mver(keyPath) { $0 = value } +} + +/// Produces a reference-mutable setter function for a given key path and new value. +/// +/// - Parameters: +/// - keyPath: A reference-writable key path. +/// - value: A new value. +/// - Returns: A reference-mutable setter function. +public func mut( + _ keyPath: ReferenceWritableKeyPath, + _ value: Value + ) + -> (Root) -> Void { + + return mver(keyPath) { $0 = value } +} diff --git a/Sources/Overture/Sequence.swift b/Sources/Overture/Sequence.swift index 540dc2a..985073f 100644 --- a/Sources/Overture/Sequence.swift +++ b/Sources/Overture/Sequence.swift @@ -22,3 +22,18 @@ public func map( return { try $0.map(transform) } } + +/// In-place collection mutation. +/// +/// - Parameter transform: A transform function. +public func mutEach( + _ transform: @escaping (inout C.Element) -> Void + ) + -> (inout C) -> Void { + + return { + for i in $0.indices { + transform(&$0[i]) + } + } +} diff --git a/Sources/Overture/Setters.swift b/Sources/Overture/Setters.swift new file mode 100644 index 0000000..db08025 --- /dev/null +++ b/Sources/Overture/Setters.swift @@ -0,0 +1,92 @@ + +/// Applies a value transformation to an immutable setter function. +/// +/// - Parameters: +/// - setter: An immutable setter function. +/// - f: A value transform function. +/// - Returns: A root transform function. +public func over( + _ setter: (@escaping (A) -> B) -> (S) -> T, + _ f: @escaping (A) -> B + ) + -> (S) -> T { + + return setter(f) +} + +/// Applies a value to an immutable setter function. +/// +/// - Parameters: +/// - setter: An immutable setter function. +/// - value: A new value. +/// - Returns: A root transform function. +public func set( + _ setter: (@escaping (A) -> B) -> (S) -> T, + _ value: B + ) + -> (S) -> T { + + return over(setter) { _ in value } +} + +// MARK: - Mutation + +/// Applies a mutable value transformation to a mutable setter function. +/// +/// - Parameters: +/// - setter: A mutable setter function. +/// - f: A mutable value transform function. +/// - Returns: A mutable root transform function. +public func mver( + _ setter: (@escaping (inout A) -> Void) -> (inout S) -> Void, + _ f: @escaping (inout A) -> Void + ) + -> (inout S) -> Void { + + return setter(f) +} + +/// Applies a mutable value transformation to a reference-mutable setter function. +/// +/// - Parameters: +/// - setter: A reference-mutable setter function. +/// - f: A mutable value transform function. +/// - Returns: A reference-mutable root transform function. +public func mver( + _ setter: (@escaping (inout A) -> Void) -> (S) -> Void, + _ f: @escaping (inout A) -> Void + ) + -> (S) -> Void { + + return setter(f) +} + +/// Applies a value to a mutable setter function. +/// +/// - Parameters: +/// - setter: An mutable setter function. +/// - value: A new value. +/// - Returns: A mutable root transform function. +public func mut( + _ setter: (@escaping (inout A) -> Void) -> (inout S) -> Void, + _ value: A + ) + -> (inout S) -> Void { + + return mver(setter) { $0 = value } +} + +/// Applies a value to a reference-mutable setter function. +/// +/// - Parameters: +/// - setter: An mutable setter function. +/// - value: A new value. +/// - Returns: A reference-mutable root transform function. +public func mut( + _ setter: (@escaping (inout A) -> Void) -> (S) -> Void, + _ value: A + ) + -> (S) -> Void { + + return mver(setter) { $0 = value } +} diff --git a/Sources/Overture/Uncurry.swift b/Sources/Overture/Uncurry.swift index c4454d1..7af6366 100644 --- a/Sources/Overture/Uncurry.swift +++ b/Sources/Overture/Uncurry.swift @@ -4,14 +4,14 @@ /// - Parameter function: A function with one argument, that returns another function with one argument. /// - Returns: An uncurried function. public func uncurry(_ function: @escaping - (A) - -> (B) - -> C) - -> (A, B) - -> C { - return { (a: A, b: B) -> C in - function(a)(b) - } + (A) + -> (B) + -> C) + -> (A, B) + -> C { + return { (a: A, b: B) -> C in + function(a)(b) + } } /// Uncurries a throwing function. @@ -19,341 +19,341 @@ public func uncurry(_ function: @escaping /// - Parameter function: A throwing function with one argument, that returns another function with one argument. /// - Returns: An uncurried, final-throwing function. public func uncurry(_ function: @escaping - (A) - -> (B) throws - -> C) - -> (A, B) throws - -> C { - return { (a: A, b: B) throws -> C in - try function(a)(b) - } + (A) + -> (B) throws + -> C) + -> (A, B) throws + -> C { + return { (a: A, b: B) throws -> C in + try function(a)(b) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> D) - -> (A, B, C) - -> D { - return { (a: A, b: B, c: C) -> D in - function(a)(b)(c) - } + (A) + -> (B) + -> (C) + -> D) + -> (A, B, C) + -> D { + return { (a: A, b: B, c: C) -> D in + function(a)(b)(c) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) throws - -> D) - -> (A, B, C) throws - -> D { - return { (a: A, b: B, c: C) throws -> D in - try function(a)(b)(c) - } + (A) + -> (B) + -> (C) throws + -> D) + -> (A, B, C) throws + -> D { + return { (a: A, b: B, c: C) throws -> D in + try function(a)(b)(c) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> E) - -> (A, B, C, D) - -> E { - return { (a: A, b: B, c: C, d: D) -> E in - function(a)(b)(c)(d) - } + (A) + -> (B) + -> (C) + -> (D) + -> E) + -> (A, B, C, D) + -> E { + return { (a: A, b: B, c: C, d: D) -> E in + function(a)(b)(c)(d) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) throws - -> E) - -> (A, B, C, D) throws - -> E { - return { (a: A, b: B, c: C, d: D) throws -> E in - try function(a)(b)(c)(d) - } + (A) + -> (B) + -> (C) + -> (D) throws + -> E) + -> (A, B, C, D) throws + -> E { + return { (a: A, b: B, c: C, d: D) throws -> E in + try function(a)(b)(c)(d) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) -> F) - -> (A, B, C, D, E) - -> F { - return { (a: A, b: B, c: C, d: D, e: E) -> F in - function(a)(b)(c)(d)(e) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) -> F) + -> (A, B, C, D, E) + -> F { + return { (a: A, b: B, c: C, d: D, e: E) -> F in + function(a)(b)(c)(d)(e) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) throws - -> F) - -> (A, B, C, D, E) throws - -> F { - return { (a: A, b: B, c: C, d: D, e: E) throws -> F in - try function(a)(b)(c)(d)(e) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) throws + -> F) + -> (A, B, C, D, E) throws + -> F { + return { (a: A, b: B, c: C, d: D, e: E) throws -> F in + try function(a)(b)(c)(d)(e) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> G) - -> (A, B, C, D, E, F) - -> G { - return { (a: A, b: B, c: C, d: D, e: E, f: F) -> G in - function(a)(b)(c)(d)(e)(f) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> G) + -> (A, B, C, D, E, F) + -> G { + return { (a: A, b: B, c: C, d: D, e: E, f: F) -> G in + function(a)(b)(c)(d)(e)(f) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) throws - -> G) - -> (A, B, C, D, E, F) throws - -> G { - return { (a: A, b: B, c: C, d: D, e: E, f: F) throws -> G in - try function(a)(b)(c)(d)(e)(f) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) throws + -> G) + -> (A, B, C, D, E, F) throws + -> G { + return { (a: A, b: B, c: C, d: D, e: E, f: F) throws -> G in + try function(a)(b)(c)(d)(e)(f) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> H) - -> (A, B, C, D, E, F, G) - -> H { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> H in - function(a)(b)(c)(d)(e)(f)(g) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> H) + -> (A, B, C, D, E, F, G) + -> H { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) -> H in + function(a)(b)(c)(d)(e)(f)(g) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) throws - -> H) - -> (A, B, C, D, E, F, G) throws - -> H { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) throws -> H in - try function(a)(b)(c)(d)(e)(f)(g) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) throws + -> H) + -> (A, B, C, D, E, F, G) throws + -> H { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G) throws -> H in + try function(a)(b)(c)(d)(e)(f)(g) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> I) - -> (A, B, C, D, E, F, G, H) - -> I { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) -> I in - function(a)(b)(c)(d)(e)(f)(g)(h) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> I) + -> (A, B, C, D, E, F, G, H) + -> I { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) -> I in + function(a)(b)(c)(d)(e)(f)(g)(h) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) throws - -> I) - -> (A, B, C, D, E, F, G, H) throws - -> I { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) throws -> I in - try function(a)(b)(c)(d)(e)(f)(g)(h) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) throws + -> I) + -> (A, B, C, D, E, F, G, H) throws + -> I { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) throws -> I in + try function(a)(b)(c)(d)(e)(f)(g)(h) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> J) - -> (A, B, C, D, E, F, G, H, I) - -> J { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) -> J in - function(a)(b)(c)(d)(e)(f)(g)(h)(i) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> J) + -> (A, B, C, D, E, F, G, H, I) + -> J { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) -> J in + function(a)(b)(c)(d)(e)(f)(g)(h)(i) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) throws - -> J) - -> (A, B, C, D, E, F, G, H, I) throws - -> J { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) throws -> J in - try function(a)(b)(c)(d)(e)(f)(g)(h)(i) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) throws + -> J) + -> (A, B, C, D, E, F, G, H, I) throws + -> J { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) throws -> J in + try function(a)(b)(c)(d)(e)(f)(g)(h)(i) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) - -> K) - -> (A, B, C, D, E, F, G, H, I, J) - -> K { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) -> K in - function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) + -> K) + -> (A, B, C, D, E, F, G, H, I, J) + -> K { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) -> K in + function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) throws - -> K) - -> (A, B, C, D, E, F, G, H, I, J) throws - -> K { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) throws -> K in - try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) throws + -> K) + -> (A, B, C, D, E, F, G, H, I, J) throws + -> K { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) throws -> K in + try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) - -> (K) - -> L) - -> (A, B, C, D, E, F, G, H, I, J, K) - -> L { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) -> L in - function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) + -> (K) + -> L) + -> (A, B, C, D, E, F, G, H, I, J, K) + -> L { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) -> L in + function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) - -> (K) throws - -> L) - -> (A, B, C, D, E, F, G, H, I, J, K) throws - -> L { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) throws -> L in - try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) + -> (K) throws + -> L) + -> (A, B, C, D, E, F, G, H, I, J, K) throws + -> L { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K) throws -> L in + try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) - -> (K) - -> (L) - -> M) - -> (A, B, C, D, E, F, G, H, I, J, K, L) - -> M { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) -> M in - function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) + -> (K) + -> (L) + -> M) + -> (A, B, C, D, E, F, G, H, I, J, K, L) + -> M { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) -> M in + function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) + } } public func uncurry(_ function: @escaping - (A) - -> (B) - -> (C) - -> (D) - -> (E) - -> (F) - -> (G) - -> (H) - -> (I) - -> (J) - -> (K) - -> (L) throws - -> M) - -> (A, B, C, D, E, F, G, H, I, J, K, L) throws - -> M { - return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) throws -> M in - try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) - } + (A) + -> (B) + -> (C) + -> (D) + -> (E) + -> (F) + -> (G) + -> (H) + -> (I) + -> (J) + -> (K) + -> (L) throws + -> M) + -> (A, B, C, D, E, F, G, H, I, J, K, L) throws + -> M { + return { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L) throws -> M in + try function(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l) + } }