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)
+ }
}