From aa1443b881b28a740e7a70ed7f0d6e3acde87d15 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 2 Jul 2015 18:30:48 -0600 Subject: [PATCH 01/14] Initial Commit --- Focus.xcodeproj/project.pbxproj | 668 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + Focus/ArrayZipper.swift | 74 ++ Focus/Focus.h | 19 + Focus/Info.plist | 28 + Focus/Iso.swift | 47 ++ Focus/IxCont.swift | 79 +++ Focus/IxMultiStore.swift | 94 +++ Focus/IxState.swift | 105 +++ Focus/IxStore.swift | 94 +++ Focus/Lens.swift | 56 ++ Focus/LensOperators.swift | 69 ++ Focus/Prism.swift | 30 + FocusTests/Info.plist | 24 + FocusTests/PartyExample.swift | 44 ++ FocusTests/UserExample.swift | 39 + 16 files changed, 1477 insertions(+) create mode 100644 Focus.xcodeproj/project.pbxproj create mode 100644 Focus.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Focus/ArrayZipper.swift create mode 100644 Focus/Focus.h create mode 100644 Focus/Info.plist create mode 100644 Focus/Iso.swift create mode 100644 Focus/IxCont.swift create mode 100644 Focus/IxMultiStore.swift create mode 100644 Focus/IxState.swift create mode 100644 Focus/IxStore.swift create mode 100644 Focus/Lens.swift create mode 100644 Focus/LensOperators.swift create mode 100644 Focus/Prism.swift create mode 100644 FocusTests/Info.plist create mode 100644 FocusTests/PartyExample.swift create mode 100644 FocusTests/UserExample.swift diff --git a/Focus.xcodeproj/project.pbxproj b/Focus.xcodeproj/project.pbxproj new file mode 100644 index 0000000..683b88c --- /dev/null +++ b/Focus.xcodeproj/project.pbxproj @@ -0,0 +1,668 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 824B45F91B460AC1009AAF49 /* Focus.h in Headers */ = {isa = PBXBuildFile; fileRef = 824B45F81B460AC1009AAF49 /* Focus.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 824B46001B460AC1009AAF49 /* Focus.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 824B45F51B460AC1009AAF49 /* Focus.framework */; }; + 824B461E1B460AFA009AAF49 /* Focus.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 824B46141B460AFA009AAF49 /* Focus.framework */; }; + 824B46321B460B25009AAF49 /* Iso.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462B1B460B25009AAF49 /* Iso.swift */; }; + 824B46331B460B25009AAF49 /* Iso.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462B1B460B25009AAF49 /* Iso.swift */; }; + 824B46341B460B25009AAF49 /* IxCont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462C1B460B25009AAF49 /* IxCont.swift */; }; + 824B46351B460B25009AAF49 /* IxCont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462C1B460B25009AAF49 /* IxCont.swift */; }; + 824B46361B460B25009AAF49 /* IxMultiStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462D1B460B25009AAF49 /* IxMultiStore.swift */; }; + 824B46371B460B25009AAF49 /* IxMultiStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462D1B460B25009AAF49 /* IxMultiStore.swift */; }; + 824B46381B460B25009AAF49 /* IxState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462E1B460B25009AAF49 /* IxState.swift */; }; + 824B46391B460B25009AAF49 /* IxState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462E1B460B25009AAF49 /* IxState.swift */; }; + 824B463A1B460B25009AAF49 /* IxStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462F1B460B25009AAF49 /* IxStore.swift */; }; + 824B463B1B460B25009AAF49 /* IxStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B462F1B460B25009AAF49 /* IxStore.swift */; }; + 824B463C1B460B25009AAF49 /* Lens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46301B460B25009AAF49 /* Lens.swift */; }; + 824B463D1B460B25009AAF49 /* Lens.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46301B460B25009AAF49 /* Lens.swift */; }; + 824B463E1B460B25009AAF49 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46311B460B25009AAF49 /* Prism.swift */; }; + 824B463F1B460B25009AAF49 /* Prism.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46311B460B25009AAF49 /* Prism.swift */; }; + 824B46421B460BE2009AAF49 /* ArrayZipper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46411B460BE2009AAF49 /* ArrayZipper.swift */; }; + 824B46431B460BE2009AAF49 /* ArrayZipper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46411B460BE2009AAF49 /* ArrayZipper.swift */; }; + 824B46481B460C1E009AAF49 /* LensOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46471B460C1E009AAF49 /* LensOperators.swift */; }; + 824B46491B460C1E009AAF49 /* LensOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B46471B460C1E009AAF49 /* LensOperators.swift */; }; + 824B464C1B460E69009AAF49 /* PartyExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B464A1B460E69009AAF49 /* PartyExample.swift */; }; + 824B464D1B460E69009AAF49 /* PartyExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B464A1B460E69009AAF49 /* PartyExample.swift */; }; + 824B464E1B460E69009AAF49 /* UserExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B464B1B460E69009AAF49 /* UserExample.swift */; }; + 824B464F1B460E69009AAF49 /* UserExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 824B464B1B460E69009AAF49 /* UserExample.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 824B46011B460AC1009AAF49 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 824B45EC1B460AC1009AAF49 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 824B45F41B460AC1009AAF49; + remoteInfo = Focus; + }; + 824B461F1B460AFA009AAF49 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 824B45EC1B460AC1009AAF49 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 824B46131B460AFA009AAF49; + remoteInfo = "Focus-iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 824B45F51B460AC1009AAF49 /* Focus.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Focus.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 824B45F81B460AC1009AAF49 /* Focus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Focus.h; path = Focus/Focus.h; sourceTree = ""; }; + 824B45FA1B460AC1009AAF49 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 824B45FF1B460AC1009AAF49 /* FocusTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FocusTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 824B46061B460AC1009AAF49 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 824B46141B460AFA009AAF49 /* Focus.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Focus.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 824B461D1B460AFA009AAF49 /* Focus-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Focus-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 824B462B1B460B25009AAF49 /* Iso.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Iso.swift; sourceTree = ""; }; + 824B462C1B460B25009AAF49 /* IxCont.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IxCont.swift; sourceTree = ""; }; + 824B462D1B460B25009AAF49 /* IxMultiStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IxMultiStore.swift; sourceTree = ""; }; + 824B462E1B460B25009AAF49 /* IxState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IxState.swift; sourceTree = ""; }; + 824B462F1B460B25009AAF49 /* IxStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IxStore.swift; sourceTree = ""; }; + 824B46301B460B25009AAF49 /* Lens.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lens.swift; sourceTree = ""; }; + 824B46311B460B25009AAF49 /* Prism.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Prism.swift; sourceTree = ""; }; + 824B46411B460BE2009AAF49 /* ArrayZipper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayZipper.swift; sourceTree = ""; }; + 824B46471B460C1E009AAF49 /* LensOperators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LensOperators.swift; sourceTree = ""; }; + 824B464A1B460E69009AAF49 /* PartyExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PartyExample.swift; sourceTree = ""; }; + 824B464B1B460E69009AAF49 /* UserExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserExample.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 824B45F11B460AC1009AAF49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B45FC1B460AC1009AAF49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B46001B460AC1009AAF49 /* Focus.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B46101B460AFA009AAF49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B461A1B460AFA009AAF49 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B461E1B460AFA009AAF49 /* Focus.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 824B45EB1B460AC1009AAF49 = { + isa = PBXGroup; + children = ( + 824B45F81B460AC1009AAF49 /* Focus.h */, + 824B45F71B460AC1009AAF49 /* Focus */, + 824B46031B460AC1009AAF49 /* FocusTests */, + 824B45F61B460AC1009AAF49 /* Products */, + ); + sourceTree = ""; + }; + 824B45F61B460AC1009AAF49 /* Products */ = { + isa = PBXGroup; + children = ( + 824B45F51B460AC1009AAF49 /* Focus.framework */, + 824B45FF1B460AC1009AAF49 /* FocusTests.xctest */, + 824B46141B460AFA009AAF49 /* Focus.framework */, + 824B461D1B460AFA009AAF49 /* Focus-iOSTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 824B45F71B460AC1009AAF49 /* Focus */ = { + isa = PBXGroup; + children = ( + 824B46411B460BE2009AAF49 /* ArrayZipper.swift */, + 824B46471B460C1E009AAF49 /* LensOperators.swift */, + 824B462B1B460B25009AAF49 /* Iso.swift */, + 824B462C1B460B25009AAF49 /* IxCont.swift */, + 824B462D1B460B25009AAF49 /* IxMultiStore.swift */, + 824B462E1B460B25009AAF49 /* IxState.swift */, + 824B462F1B460B25009AAF49 /* IxStore.swift */, + 824B46301B460B25009AAF49 /* Lens.swift */, + 824B46311B460B25009AAF49 /* Prism.swift */, + 824B46401B460B28009AAF49 /* Supporting Files */, + ); + path = Focus; + sourceTree = ""; + }; + 824B46031B460AC1009AAF49 /* FocusTests */ = { + isa = PBXGroup; + children = ( + 824B464A1B460E69009AAF49 /* PartyExample.swift */, + 824B464B1B460E69009AAF49 /* UserExample.swift */, + 824B46061B460AC1009AAF49 /* Info.plist */, + ); + path = FocusTests; + sourceTree = ""; + }; + 824B46401B460B28009AAF49 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 824B45FA1B460AC1009AAF49 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 824B45F21B460AC1009AAF49 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B45F91B460AC1009AAF49 /* Focus.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B46111B460AFA009AAF49 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 824B45F41B460AC1009AAF49 /* Focus */ = { + isa = PBXNativeTarget; + buildConfigurationList = 824B46091B460AC1009AAF49 /* Build configuration list for PBXNativeTarget "Focus" */; + buildPhases = ( + 824B45F01B460AC1009AAF49 /* Sources */, + 824B45F11B460AC1009AAF49 /* Frameworks */, + 824B45F21B460AC1009AAF49 /* Headers */, + 824B45F31B460AC1009AAF49 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Focus; + productName = Focus; + productReference = 824B45F51B460AC1009AAF49 /* Focus.framework */; + productType = "com.apple.product-type.framework"; + }; + 824B45FE1B460AC1009AAF49 /* FocusTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 824B460C1B460AC1009AAF49 /* Build configuration list for PBXNativeTarget "FocusTests" */; + buildPhases = ( + 824B45FB1B460AC1009AAF49 /* Sources */, + 824B45FC1B460AC1009AAF49 /* Frameworks */, + 824B45FD1B460AC1009AAF49 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 824B46021B460AC1009AAF49 /* PBXTargetDependency */, + ); + name = FocusTests; + productName = FocusTests; + productReference = 824B45FF1B460AC1009AAF49 /* FocusTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 824B46131B460AFA009AAF49 /* Focus-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 824B46291B460AFA009AAF49 /* Build configuration list for PBXNativeTarget "Focus-iOS" */; + buildPhases = ( + 824B460F1B460AFA009AAF49 /* Sources */, + 824B46101B460AFA009AAF49 /* Frameworks */, + 824B46111B460AFA009AAF49 /* Headers */, + 824B46121B460AFA009AAF49 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Focus-iOS"; + productName = "Focus-iOS"; + productReference = 824B46141B460AFA009AAF49 /* Focus.framework */; + productType = "com.apple.product-type.framework"; + }; + 824B461C1B460AFA009AAF49 /* Focus-iOSTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 824B462A1B460AFA009AAF49 /* Build configuration list for PBXNativeTarget "Focus-iOSTests" */; + buildPhases = ( + 824B46191B460AFA009AAF49 /* Sources */, + 824B461A1B460AFA009AAF49 /* Frameworks */, + 824B461B1B460AFA009AAF49 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 824B46201B460AFA009AAF49 /* PBXTargetDependency */, + ); + name = "Focus-iOSTests"; + productName = "Focus-iOSTests"; + productReference = 824B461D1B460AFA009AAF49 /* Focus-iOSTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 824B45EC1B460AC1009AAF49 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = TypeLift; + TargetAttributes = { + 824B45F41B460AC1009AAF49 = { + CreatedOnToolsVersion = 7.0; + }; + 824B45FE1B460AC1009AAF49 = { + CreatedOnToolsVersion = 7.0; + }; + 824B46131B460AFA009AAF49 = { + CreatedOnToolsVersion = 7.0; + }; + 824B461C1B460AFA009AAF49 = { + CreatedOnToolsVersion = 7.0; + }; + }; + }; + buildConfigurationList = 824B45EF1B460AC1009AAF49 /* Build configuration list for PBXProject "Focus" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 824B45EB1B460AC1009AAF49; + productRefGroup = 824B45F61B460AC1009AAF49 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 824B45F41B460AC1009AAF49 /* Focus */, + 824B45FE1B460AC1009AAF49 /* FocusTests */, + 824B46131B460AFA009AAF49 /* Focus-iOS */, + 824B461C1B460AFA009AAF49 /* Focus-iOSTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 824B45F31B460AC1009AAF49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B45FD1B460AC1009AAF49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B46121B460AFA009AAF49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B461B1B460AFA009AAF49 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 824B45F01B460AC1009AAF49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B46361B460B25009AAF49 /* IxMultiStore.swift in Sources */, + 824B463E1B460B25009AAF49 /* Prism.swift in Sources */, + 824B46341B460B25009AAF49 /* IxCont.swift in Sources */, + 824B46381B460B25009AAF49 /* IxState.swift in Sources */, + 824B46321B460B25009AAF49 /* Iso.swift in Sources */, + 824B46421B460BE2009AAF49 /* ArrayZipper.swift in Sources */, + 824B463A1B460B25009AAF49 /* IxStore.swift in Sources */, + 824B46481B460C1E009AAF49 /* LensOperators.swift in Sources */, + 824B463C1B460B25009AAF49 /* Lens.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B45FB1B460AC1009AAF49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B464C1B460E69009AAF49 /* PartyExample.swift in Sources */, + 824B464E1B460E69009AAF49 /* UserExample.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B460F1B460AFA009AAF49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B46371B460B25009AAF49 /* IxMultiStore.swift in Sources */, + 824B463F1B460B25009AAF49 /* Prism.swift in Sources */, + 824B46351B460B25009AAF49 /* IxCont.swift in Sources */, + 824B46391B460B25009AAF49 /* IxState.swift in Sources */, + 824B46331B460B25009AAF49 /* Iso.swift in Sources */, + 824B46431B460BE2009AAF49 /* ArrayZipper.swift in Sources */, + 824B463B1B460B25009AAF49 /* IxStore.swift in Sources */, + 824B46491B460C1E009AAF49 /* LensOperators.swift in Sources */, + 824B463D1B460B25009AAF49 /* Lens.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 824B46191B460AFA009AAF49 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 824B464D1B460E69009AAF49 /* PartyExample.swift in Sources */, + 824B464F1B460E69009AAF49 /* UserExample.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 824B46021B460AC1009AAF49 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 824B45F41B460AC1009AAF49 /* Focus */; + targetProxy = 824B46011B460AC1009AAF49 /* PBXContainerItemProxy */; + }; + 824B46201B460AFA009AAF49 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 824B46131B460AFA009AAF49 /* Focus-iOS */; + targetProxy = 824B461F1B460AFA009AAF49 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 824B46071B460AC1009AAF49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 824B46081B460AC1009AAF49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.10; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 824B460A1B460AC1009AAF49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Focus/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.TypeLift.Focus; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 824B460B1B460AC1009AAF49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Focus/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.TypeLift.Focus; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 824B460D1B460AC1009AAF49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = FocusTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.TypeLift.FocusTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 824B460E1B460AC1009AAF49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = FocusTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.TypeLift.FocusTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 824B46251B460AFA009AAF49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Focus/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.TypeLift.Focus-iOS"; + PRODUCT_NAME = Focus; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 824B46261B460AFA009AAF49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Focus/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.TypeLift.Focus-iOS"; + PRODUCT_NAME = Focus; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 824B46271B460AFA009AAF49 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = FocusTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.TypeLift.Focus-iOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 824B46281B460AFA009AAF49 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + INFOPLIST_FILE = FocusTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.TypeLift.Focus-iOSTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 824B45EF1B460AC1009AAF49 /* Build configuration list for PBXProject "Focus" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 824B46071B460AC1009AAF49 /* Debug */, + 824B46081B460AC1009AAF49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 824B46091B460AC1009AAF49 /* Build configuration list for PBXNativeTarget "Focus" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 824B460A1B460AC1009AAF49 /* Debug */, + 824B460B1B460AC1009AAF49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 824B460C1B460AC1009AAF49 /* Build configuration list for PBXNativeTarget "FocusTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 824B460D1B460AC1009AAF49 /* Debug */, + 824B460E1B460AC1009AAF49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 824B46291B460AFA009AAF49 /* Build configuration list for PBXNativeTarget "Focus-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 824B46251B460AFA009AAF49 /* Debug */, + 824B46261B460AFA009AAF49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 824B462A1B460AFA009AAF49 /* Build configuration list for PBXNativeTarget "Focus-iOSTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 824B46271B460AFA009AAF49 /* Debug */, + 824B46281B460AFA009AAF49 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 824B45EC1B460AC1009AAF49 /* Project object */; +} diff --git a/Focus.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Focus.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..50f4d2c --- /dev/null +++ b/Focus.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Focus/ArrayZipper.swift b/Focus/ArrayZipper.swift new file mode 100644 index 0000000..4daeeeb --- /dev/null +++ b/Focus/ArrayZipper.swift @@ -0,0 +1,74 @@ +// +// ArrayZipper.swift +// swiftz +// +// Created by Alexander Ronald Altman on 8/4/14. +// Copyright (c) 2014 Maxwell Swadling. All rights reserved. +// + +/// A zipper for arrays. Zippers are convenient ways of traversing and modifying the parts of a +/// structure using a cursor to focus on its individual parts. +public struct ArrayZipper : ArrayLiteralConvertible { + typealias Element = A + + public let values : [A] + public let position : Int + + public init(_ values : [A] = [], _ position : Int = 0) { + if position < 0 { + self.position = 0 + } else if position >= values.count { + self.position = values.count - 1 + } else { + self.position = position + } + self.values = values + } + + public init(arrayLiteral elements : Element...) { + self.init(elements, 0) + } + + public func move(n : Int = 1) -> ArrayZipper { + return ArrayZipper(values, position + n) + } + + public func moveTo(pos : Int) -> ArrayZipper { + return ArrayZipper(values, pos) + } +} + +extension ArrayZipper /*: Functor*/ { + typealias B = Any + typealias FB = ArrayZipper + + public func fmap(f : A -> B) -> ArrayZipper { + return ArrayZipper(self.values.map(f), self.position) + } +} + +public func <^> (f : A -> B, xz : ArrayZipper) -> ArrayZipper { + return xz.fmap(f) +} + +extension ArrayZipper /*: Copointed*/ { + public func extract() -> A { + return self.values[self.position] + } +} + +extension ArrayZipper /*: Comonad*/ { + typealias FFA = ArrayZipper> + + public func duplicate() -> ArrayZipper> { + return ArrayZipper>((0 ..< self.values.count).map { ArrayZipper(self.values, $0) }, self.position) + } + + public func extend(f : ArrayZipper -> B) -> ArrayZipper { + return ArrayZipper((0 ..< self.values.count).map { f(ArrayZipper(self.values, $0)) }, self.position) + } +} + +public func ->> (xz : ArrayZipper, f: ArrayZipper -> B) -> ArrayZipper { + return xz.extend(f) +} diff --git a/Focus/Focus.h b/Focus/Focus.h new file mode 100644 index 0000000..22a0439 --- /dev/null +++ b/Focus/Focus.h @@ -0,0 +1,19 @@ +// +// Focus.h +// Focus +// +// Created by Robert Widmann on 7/2/15. +// Copyright © 2015 TypeLift. All rights reserved. +// + +#import + +//! Project version number for Focus. +FOUNDATION_EXPORT double FocusVersionNumber; + +//! Project version string for Focus. +FOUNDATION_EXPORT const unsigned char FocusVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Focus/Info.plist b/Focus/Info.plist new file mode 100644 index 0000000..8d41819 --- /dev/null +++ b/Focus/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright + Copyright © 2015 TypeLift. All rights reserved. + NSPrincipalClass + + + diff --git a/Focus/Iso.swift b/Focus/Iso.swift new file mode 100644 index 0000000..2c75326 --- /dev/null +++ b/Focus/Iso.swift @@ -0,0 +1,47 @@ +// +// Iso.swift +// swiftz +// +// Created by Alexander Ronald Altman on 7/22/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + +/// Captures an isomorphism between S and A and +public struct Iso { + public let get : S -> A + public let inject : B -> T + + /// Builds an Iso from a pair of inverse functions. + public init(get : S -> A, inject : B -> T) { + self.get = get + self.inject = inject + } + + + public func modify(v : S, _ f : A -> B) -> T { + return inject(f(get(v))) + } + + public var asLens : Lens { + return Lens { s in IxStore(self.get(s)) { self.inject($0) } } + } + + public var asPrism : Prism { + return Prism(tryGet: { .Some(self.get($0)) }, inject: inject) + } +} + +/// The identity isomorphism. +public func identity() -> Iso { + return Iso(get: identity, inject: identity) +} + +/// Compose isomorphisms. +public func • (i1 : Iso, i2 : Iso) -> Iso { + return Iso(get: i2.get • i1.get, inject: i1.inject • i2.inject) +} + +/// Compose isomorphisms. +public func comp(i1 : Iso)(i2 : Iso) -> Iso { + return i1 • i2 +} diff --git a/Focus/IxCont.swift b/Focus/IxCont.swift new file mode 100644 index 0000000..6450fdd --- /dev/null +++ b/Focus/IxCont.swift @@ -0,0 +1,79 @@ +// +// IxCont.swift +// swiftz +// +// Created by Alexander Ronald Altman on 6/10/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + +public struct IxCont { + let run: (A -> O) -> R + + public init(_ run: (A -> O) -> R) { + self.run = run + } + + public func map(f : A -> B) -> IxCont { + return f <^> self + } + + public func imap(f : R -> S) -> IxCont { + return f <^^> self + } + + public func contramap(f : N -> O) -> IxCont { + return f self + } + + public func ap(f : IxCont B>) -> IxCont { + return f <*> self + } + + public func flatMap(f : A -> IxCont) -> IxCont { + return self >>- f + } +} + +public func run(a : IxCont) -> R { + return a.run(identity) +} + +public func pure(x : A) -> IxCont { + return IxCont { $0(x) } +} + +public func <^> (f : A -> B, a: IxCont) -> IxCont { + return IxCont { k in a.run { k(f($0)) } } +} + +public func <^^> (f : R -> S, a: IxCont) -> IxCont { + return IxCont { f(a.run($0)) } +} + +public func (f : N -> O, a: IxCont) -> IxCont { + return IxCont { k in a.run { f(k($0)) } } +} + +public func <*> (f : IxCont B>, a: IxCont) -> IxCont { + return IxCont { k in f.run { g in a.run { k(g($0)) } } } +} + +public func >>- (a : IxCont, f: A -> IxCont) -> IxCont { + return IxCont { k in a.run { f($0).run(k) } } +} + +public func join(a : IxCont>) -> IxCont { + return IxCont { k in a.run { $0.run(k) } } +} + +public func shift(f : (A -> IxCont) -> IxCont) -> IxCont { + return IxCont { k in run(f { pure(k($0)) }) } +} + +public func reset(a : IxCont) -> IxCont { + return pure(run(a)) +} + +public func callCC(f : (A -> IxCont) -> IxCont) -> IxCont { + return IxCont { k in (f { x in IxCont { _ in k(x) } }).run(k) } +} diff --git a/Focus/IxMultiStore.swift b/Focus/IxMultiStore.swift new file mode 100644 index 0000000..7f6680b --- /dev/null +++ b/Focus/IxMultiStore.swift @@ -0,0 +1,94 @@ +// +// IxMultiStore.swift +// swiftz +// +// Created by Alexander Ronald Altman on 8/4/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + + +// N.B.: This is the "inlining" of the indexed store comonad transformer +// applied to the array zipper comonad +public struct IxMultiStore { + let pos : O + + let set : ArrayZipper A> + + public init(_ pos: O, _ set: ArrayZipper A>) { + self.pos = pos + self.set = set + } + + public func map(f : A -> B) -> IxMultiStore { + return f <^> self + } + + public func imap

(f : O -> P) -> IxMultiStore { + return f <^^> self + } + + public func contramap(f : H -> I) -> IxMultiStore { + return f self + } + + public func dup() -> IxMultiStore> { + return duplicate(self) + } + + public func extend(f : IxMultiStore -> B) -> IxMultiStore { + return self ->> f + } + + public func put(x : I) -> ArrayZipper { + return { $0(x) } <^> set + } + + public func puts(f : O -> I) -> ArrayZipper { + return put(f(pos)) + } + + public func peek(x : I) -> A { + return put(x).extract() + } + + public func peeks(f : O -> I) -> A { + return peek(f(pos)) + } +} + +public func extract(a : IxMultiStore) -> A { + return a.set.extract()(a.pos) +} + +public func <^> (f : A -> B, a : IxMultiStore) -> IxMultiStore { + return IxMultiStore(a.pos, { g in { f(g($0)) } } <^> a.set) +} + +public func<^^>(f : O -> P, a : IxMultiStore) -> IxMultiStore { + return IxMultiStore(f(a.pos), a.set) +} + +public func (f : H -> I, a : IxMultiStore) -> IxMultiStore { + return IxMultiStore(a.pos, { $0 • f } <^> a.set) +} + +public func duplicate(a : IxMultiStore) -> IxMultiStore> { + return IxMultiStore(a.pos, a.set ->> { g in { IxMultiStore($0, g) } }) +} + +public func ->> (a : IxMultiStore, f : IxMultiStore -> B) -> IxMultiStore { + return IxMultiStore(a.pos, a.set ->> { g in { f(IxMultiStore($0, g)) } }) +} + +public func lower(a : IxMultiStore) -> ArrayZipper { + return { $0(a.pos) } <^> a.set +} + +public func seek(a : IxMultiStore)(x : P) -> IxMultiStore { + return IxMultiStore(x, a.set) +} + +public func seeks(a : IxMultiStore)(f : O -> P) -> IxMultiStore { + return IxMultiStore(f(a.pos), a.set) +} + diff --git a/Focus/IxState.swift b/Focus/IxState.swift new file mode 100644 index 0000000..f3b15ff --- /dev/null +++ b/Focus/IxState.swift @@ -0,0 +1,105 @@ +// +// IxState.swift +// swiftz +// +// Created by Alexander Ronald Altman on 6/11/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + +/// IxState is a State Monad that carries extra type-level state through its computation. +public struct IxState { + let run : I -> (A, O) + + public init(_ run : I -> (A, O)) { + self.run = run + } + + public func eval(s : I) -> A { + return run(s).0 + } + + public func exec(s : I) -> O { + return run(s).1 + } + + public func map(f : A -> B) -> IxState { + return f <^> self + } + + public func contramap(f : H -> I) -> IxState { + return f self + } + + public func imap

(f : O -> P) -> IxState { + return f <^^> self + } + + public func ap(f : IxState B>) -> IxState { + return f <*> self + } + + public func flatMap(f : A -> IxState) -> IxState { + return self >>- f + } + +} + +public func pure(x : A) -> IxState { + return IxState { (x, $0) } +} + +public func <^> (f : A -> B, a : IxState) -> IxState { + return IxState { s1 in + let (x, s2) = a.run(s1) + return (f(x), s2) + } +} + +public func (f : H -> I, a : IxState) -> IxState { + return IxState { a.run(f($0)) } +} + +public func <^^> (f : O -> P, a : IxState) -> IxState { + return IxState { s1 in + let (x, s2) = a.run(s1) + return (x, f(s2)) + } +} + +public func <*> (f : IxState B>, a : IxState) -> IxState { + return IxState { s1 in + let (g, s2) = f.run(s1) + let (x, s3) = a.run(s2) + return (g(x), s3) + } +} + +public func >>- (a : IxState, f : A -> IxState) -> IxState { + return IxState { s1 in + let (x, s2) = a.run(s1) + return f(x).run(s2) + } +} + +public func join(a : IxState>) -> IxState { + return IxState { s1 in + let (b, s2) = a.run(s1) + return b.run(s2) + } +} + +public func get() -> IxState { + return IxState { ($0, $0) } +} + +public func gets(f : I -> A) -> IxState { + return IxState { (f($0), $0) } +} + +public func put(s : O) -> IxState { + return IxState { _ in ((), s) } +} + +public func modify(f : I -> O) -> IxState { + return IxState { ((), f($0)) } +} diff --git a/Focus/IxStore.swift b/Focus/IxStore.swift new file mode 100644 index 0000000..8256b75 --- /dev/null +++ b/Focus/IxStore.swift @@ -0,0 +1,94 @@ +// +// IxStore.swift +// swiftz +// +// Created by Alexander Ronald Altman on 6/12/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + + +// N.B.: In the indexed store comonad transformer, set, put, and peek are all distinct, +// as are puts and peeks. The lack of distinction here is due to the lack of transformer +// nature; as soon as we get transformers, that will change. +public struct IxStore { + let pos : O + + let set : I -> A + + public init(_ pos: O, _ set: I -> A) { + self.pos = pos + self.set = set + } + + public func map(f : A -> B) -> IxStore { + return f <^> self + } + + public func imap

(f : O -> P) -> IxStore { + return f <^^> self + } + + public func contramap(f : H -> I) -> IxStore { + return f self + } + + public func dup() -> IxStore> { + return duplicate(self) + } + + public func extend(f : IxStore -> B) -> IxStore { + return self ->> f + } + + public func put(x : I) -> A { + return set(x) + } + + public func puts(f : O -> I) -> A { + return set(f(pos)) + } + + public func peek(x : I) -> A { + return set(x) + } + + public func peeks(f : O -> I) -> A { + return set(f(pos)) + } +} + +public func trivial(x : A) -> IxStore { + return IxStore(x, identity) +} + +public func extract(a : IxStore) -> A { + return a.set(a.pos) +} + +public func <^> (f : A -> B, a : IxStore) -> IxStore { + return IxStore(a.pos) { f(a.set($0)) } +} + +public func<^^>(f : O -> P, a : IxStore) -> IxStore { + return IxStore(f(a.pos), a.set) +} + +public func (f : H -> I, a : IxStore) -> IxStore { + return IxStore(a.pos) { a.set(f($0)) } +} + +public func duplicate(a : IxStore) -> IxStore> { + return IxStore(a.pos) { IxStore($0, a.set) } +} + +public func ->> (a : IxStore, f : IxStore -> B) -> IxStore { + return IxStore(a.pos) { f(IxStore($0, a.set)) } +} + +public func seek(a : IxStore)(x : P) -> IxStore { + return IxStore(x, a.set) +} + +public func seeks(a : IxStore)(f : O -> P) -> IxStore { + return IxStore(f(a.pos), a.set) +} diff --git a/Focus/Lens.swift b/Focus/Lens.swift new file mode 100644 index 0000000..559ebf9 --- /dev/null +++ b/Focus/Lens.swift @@ -0,0 +1,56 @@ +// +// Lens.swift +// swiftz +// +// Created by Maxwell Swadling on 8/06/2014. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + +public struct Lens { + public let run : S -> IxStore + + public init(_ run : S -> IxStore) { + self.run = run + } + + public init(get : S -> A, set : (S, B) -> T) { + self.init({ v in IxStore(get(v)) { set(v, $0) } }) + } + + public init(get : S -> A, modify : (S, A -> B) -> T) { + self.init(get : get, set : { v, x in modify(v) { _ in x } }) + } + + public func get(v : S) -> A { + return run(v).pos + } + + public func set(v : S, _ x: B) -> T { + return run(v).peek(x) + } + + public func modify(v : S, _ f: A -> B) -> T { + let q = run(v) + return q.peek(f(q.pos)) + } + + public func zoom(a : IxState) -> IxState { + return IxState { s1 in + let q = self.run(s1) + let (x, s2) = a.run(q.pos) + return (x, q.peek(s2)) + } + } +} + +public func • (l1 : Lens, l2 : Lens) -> Lens { + return Lens { v in + let q1 = l1.run(v) + let q2 = l2.run(q1.pos) + return IxStore(q2.pos) { q1.peek(q2.peek($0)) } + } +} + +public func comp(l1 : Lens)(l2 : Lens) -> Lens { + return l1 • l2 +} diff --git a/Focus/LensOperators.swift b/Focus/LensOperators.swift new file mode 100644 index 0000000..c3d062c --- /dev/null +++ b/Focus/LensOperators.swift @@ -0,0 +1,69 @@ +// +// Operator.swift +// Focus +// +// Created by Robert Widmann on 7/2/15. +// Copyright © 2015 TypeLift. All rights reserved. +// + +/// Compose | Applies one function to the result of another function to produce a third function. +infix operator • { + associativity right + precedence 190 +} + +/// MARK: Control.* + +/// Fmap | Maps a function over the value encapsulated by a functor. +infix operator <^> { + associativity left + precedence 140 +} + +/// Imap | Maps covariantly over the index of a right-leaning bifunctor. +infix operator <^^> { + associativity left + precedence 140 +} + +/// Contramap | Contravariantly maps a function over the value encapsulated by a functor. +infix operator { + associativity left + precedence 140 +} + +/// Ap | Applies a function encapsulated by a functor to the value encapsulated by another functor. +infix operator <*> { + associativity left + precedence 140 +} + +/// Bind | Sequences and composes two monadic actions by passing the value inside the monad on the +/// left to a function on the right yielding a new monad. +infix operator >>- { + associativity left + precedence 110 +} + +/// Extend | Duplicates the surrounding context and computes a value from it while remaining in the +/// original context. +infix operator ->> { + associativity left + precedence 110 +} + +/// The identity function. +internal func identity(a : A) -> A { + return a +} + +/// Compose | Applies one function to the result of another function to produce a third function. +/// +/// f : B -> C +/// g : A -> B +/// (f • g)(x) === f(g(x)) : A -> B -> C +internal func • (f : B -> C, g: A -> B) -> A -> C { + return { (a : A) -> C in + return f(g(a)) + } +} \ No newline at end of file diff --git a/Focus/Prism.swift b/Focus/Prism.swift new file mode 100644 index 0000000..721a5d2 --- /dev/null +++ b/Focus/Prism.swift @@ -0,0 +1,30 @@ +// +// Prism.swift +// swiftz +// +// Created by Alexander Ronald Altman on 7/22/14. +// Copyright (c) 2015 TypeLift. All rights reserved. +// + + +public struct Prism { + public let tryGet : S -> A? + public let inject : B -> T + + public init(tryGet : S -> A?, inject : B -> T) { + self.tryGet = tryGet + self.inject = inject + } + + public func tryModify(s : S, _ f : A -> B) -> T? { + return tryGet(s).map(self.inject • f) + } +} + +public func • (p1 : Prism, p2 : Prism) -> Prism { + return Prism(tryGet: { p1.tryGet($0).flatMap(p2.tryGet) }, inject: p1.inject • p2.inject) +} + +public func comp(p1 : Prism)(p2 : Prism) -> Prism { + return p1 • p2 +} diff --git a/FocusTests/Info.plist b/FocusTests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/FocusTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/FocusTests/PartyExample.swift b/FocusTests/PartyExample.swift new file mode 100644 index 0000000..b0881b0 --- /dev/null +++ b/FocusTests/PartyExample.swift @@ -0,0 +1,44 @@ +// +// PartyExample.swift +// swiftz +// +// Created by Maxwell Swadling on 9/06/2014. +// Copyright (c) 2014 Maxwell Swadling. All rights reserved. +// + +import XCTest +import Focus + +// A party has a host, who is a user. +// A lens example +class Party { + let host : User + + init(h : User) { + host = h + } + + class func lpartyHost() -> Lens { + let getter = { (party: Party) -> User in + party.host + } + + let setter = { (party: Party, host: User) -> Party in + Party(h: host) + } + + return Lens(get: getter, set: setter) + } +} + +class PartySpec : XCTestCase { + func testLens() { + let party = Party(h: User("max", 1, [], "one")) + let hostnameLens = Party.lpartyHost() • User.luserName() + + XCTAssert(hostnameLens.get(party) == "max") + + let updatedParty: Party = (Party.lpartyHost() • User.luserName()).set(party, "Max") + XCTAssert(hostnameLens.get(updatedParty) == "Max") + } +} diff --git a/FocusTests/UserExample.swift b/FocusTests/UserExample.swift new file mode 100644 index 0000000..1aec11f --- /dev/null +++ b/FocusTests/UserExample.swift @@ -0,0 +1,39 @@ +// +// UserExample.swift +// swiftz +// +// Created by Maxwell Swadling on 9/06/2014. +// Copyright (c) 2014 Maxwell Swadling. All rights reserved. +// + +import Focus + +// A user example +// an example of why we need SYB, Generics or macros +public class User { + let name : String + let age : Int + let tweets : [String] + let attr : String + + public init(_ n : String, _ a : Int, _ t : [String], _ r : String) { + name = n + age = a + tweets = t + attr = r + } + + // JSON + public class func create(x : String) -> Int -> ([String] -> String -> User) { + return { y in { z in { User(x, y, z, $0) } } } + } + + // lens example + public class func luserName() -> Lens { + return Lens { user in IxStore(user.name) { User($0, user.age, user.tweets, user.attr) } } + } +} + +public func ==(lhs : User, rhs : User) -> Bool { + return lhs.name == rhs.name && lhs.age == rhs.age && lhs.tweets == rhs.tweets && lhs.attr == rhs.attr +} From f59594726110c26f43b227649e12de59d383ce44 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 12:12:31 -0600 Subject: [PATCH 02/14] Document Iso --- Focus/Iso.swift | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Focus/Iso.swift b/Focus/Iso.swift index 2c75326..11e3e6e 100644 --- a/Focus/Iso.swift +++ b/Focus/Iso.swift @@ -6,7 +6,7 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// Captures an isomorphism between S and A and +/// Captures an isomorphism between S and A. public struct Iso { public let get : S -> A public let inject : B -> T @@ -17,15 +17,22 @@ public struct Iso { self.inject = inject } - + /// Runs a value S along both parts of the Iso. public func modify(v : S, _ f : A -> B) -> T { return inject(f(get(v))) } - public var asLens : Lens { - return Lens { s in IxStore(self.get(s)) { self.inject($0) } } - } - + /// Composes an `Iso` with the receiver. + public func compose(i2 : Iso) -> Iso { + return self • i2 + } + + /// Converts an Iso to a Lens. + public var asLens : Lens { + return Lens { s in IxStore(self.get(s)) { self.inject($0) } } + } + + /// Converts an Iso to a Prism with a getter that always succeeds.. public var asPrism : Prism { return Prism(tryGet: { .Some(self.get($0)) }, inject: inject) } @@ -40,8 +47,3 @@ public func identity() -> Iso { public func • (i1 : Iso, i2 : Iso) -> Iso { return Iso(get: i2.get • i1.get, inject: i1.inject • i2.inject) } - -/// Compose isomorphisms. -public func comp(i1 : Iso)(i2 : Iso) -> Iso { - return i1 • i2 -} From 8ddb4c2583ec4f194e0ca6ba610c07217fe41718 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 12:26:34 -0600 Subject: [PATCH 03/14] Document IxCont --- Focus/Iso.swift | 3 ++- Focus/IxCont.swift | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Focus/Iso.swift b/Focus/Iso.swift index 11e3e6e..4ad47d1 100644 --- a/Focus/Iso.swift +++ b/Focus/Iso.swift @@ -8,6 +8,7 @@ /// Captures an isomorphism between S and A. public struct Iso { + /// public let get : S -> A public let inject : B -> T @@ -17,7 +18,7 @@ public struct Iso { self.inject = inject } - /// Runs a value S along both parts of the Iso. + /// Runs a value of type `S` along both parts of the Iso. public func modify(v : S, _ f : A -> B) -> T { return inject(f(get(v))) } diff --git a/Focus/IxCont.swift b/Focus/IxCont.swift index 6450fdd..39ba0c4 100644 --- a/Focus/IxCont.swift +++ b/Focus/IxCont.swift @@ -6,29 +6,39 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +/// `IxCont` is the Continuation Monad indexed by a result type `R`, an immediate output type `O` +/// and a value `A`. public struct IxCont { - let run: (A -> O) -> R + /// Lowers an `IxCont` to an indexed continuation function. + public let run : (A -> O) -> R - public init(_ run: (A -> O) -> R) { + /// Lifts an indexed continuation function into an `IxCont`. + public init(_ run : (A -> O) -> R) { self.run = run } + /// Applies a function that transforms the input value of the continuation function. public func map(f : A -> B) -> IxCont { return f <^> self } + /// Applies a function that transforms the final output value of the continuation function. public func imap(f : R -> S) -> IxCont { return f <^^> self } + /// Applies a function that transforms the immediate output value of the continuation function. public func contramap(f : N -> O) -> IxCont { return f self } + /// Composes two continuation functions by applying the final result of the second to the + /// immediate value of the first then running both continuations in series. public func ap(f : IxCont B>) -> IxCont { return f <*> self } + /// Fits the receiver together with a second continuation and runs them in series. public func flatMap(f : A -> IxCont) -> IxCont { return self >>- f } From 5b1203fc5fa3246d099c3fbe1a7d929ed9bb9f2c Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 13:52:05 -0600 Subject: [PATCH 04/14] Document IxState --- Focus/IxState.swift | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Focus/IxState.swift b/Focus/IxState.swift index f3b15ff..3c8f8bc 100644 --- a/Focus/IxState.swift +++ b/Focus/IxState.swift @@ -6,38 +6,52 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // -/// IxState is a State Monad that carries extra type-level state through its computation. +/// IxState is a State Monad that carries extra type-level state (`I`) through its computation. public struct IxState { + /// Extracts a final value and state given an index. let run : I -> (A, O) + /// Lifts an indexed state computation into an `IxState`. public init(_ run : I -> (A, O)) { self.run = run } + /// Evaluates the receiver's underlying state computation with the given index and returns the + /// final value, discarding the final state. public func eval(s : I) -> A { return run(s).0 } + /// Evaluates the receiver's underlying state computation with the given index and returns the + /// final state, discarding the final value. public func exec(s : I) -> O { return run(s).1 } + /// Applies a function to the final value generated by the receiver's underlying state + /// computation. public func map(f : A -> B) -> IxState { return f <^> self } + /// Uses the function to witness a new `IxState` indexed by a different type. public func contramap(f : H -> I) -> IxState { return f self } + /// Applies a function to the final state value generated by the receivers underlying state + /// computation. public func imap

(f : O -> P) -> IxState { return f <^^> self } + /// Runs both stateful computations, applying the resulting function to the final value of the + /// receiver. public func ap(f : IxState B>) -> IxState { return f <*> self } + /// Uses the final value of the receiver to produce another stateful computation. public func flatMap(f : A -> IxState) -> IxState { return self >>- f } From a574e6281d4ac43f493cbccf92319f94aa0d09df Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 13:52:13 -0600 Subject: [PATCH 05/14] Document IxStore --- Focus/IxStore.swift | 75 +++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/Focus/IxStore.swift b/Focus/IxStore.swift index 8256b75..2d531cb 100644 --- a/Focus/IxStore.swift +++ b/Focus/IxStore.swift @@ -6,13 +6,17 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - -// N.B.: In the indexed store comonad transformer, set, put, and peek are all distinct, -// as are puts and peeks. The lack of distinction here is due to the lack of transformer -// nature; as soon as we get transformers, that will change. +/// An `IxStore` models a store of variables of type `A` each at an index of type `I`. Unlike the +/// Costate Comonad, `IxStore`'s position is indexed by a type `O`. +/// +/// N.B.: In the indexed store comonad transformer, set, put, and peek are all distinct, +/// as are puts and peeks. The lack of distinction here is due to the lack of transformer +/// nature; as soon as we get transformers, that will change. public struct IxStore { + /// The current position of the receiver. let pos : O + /// Retrieves the value at index `I`. let set : I -> A public init(_ pos: O, _ set: I -> A) { @@ -20,47 +24,78 @@ public struct IxStore { self.set = set } + /// Applies a function to the retrieval of values. public func map(f : A -> B) -> IxStore { return f <^> self } + /// Applies a function to the position index. public func imap

(f : O -> P) -> IxStore { return f <^^> self } + /// Applies a function to the retrieval index. public func contramap(f : H -> I) -> IxStore { return f self } - public func dup() -> IxStore> { - return duplicate(self) + /// Returns an `IxStore` that retrieves + public func duplicate() -> IxStore> { + return IxStore>(pos) { IxStore($0, self.set) } } + /// Extends the context of the store with a function that retrieves values from another store + /// indexed by a different position. public func extend(f : IxStore -> B) -> IxStore { return self ->> f } + /// Extracts a value from the store at a given index. + public func peek(x : I) -> A { + return set(x) + } + + /// Extracts a value from the store at an index given by applying a function to the receiver's + /// position index. + public func peeks(f : O -> I) -> A { + return set(f(pos)) + } + + /// Extracts a value from the store at a given index. + /// + /// With a proper Monad Transformer this function would use a Comonadic context to extract a + /// value. public func put(x : I) -> A { return set(x) } + /// Extracts a value from the store at an index given by applying a function to the receiver's + /// position index. + /// + /// With a proper Monad Transformer this function would use a Comonadic context to extract a + /// value. public func puts(f : O -> I) -> A { return set(f(pos)) } - public func peek(x : I) -> A { - return set(x) - } - - public func peeks(f : O -> I) -> A { - return set(f(pos)) - } + /// Returns a new `IxStore` with its position index set to the given value. + public func seek

(x : P) -> IxStore { + return IxStore(x, set) + } + + /// Returns a new `IxStore` with its position index set to the result of applying the given + /// function to the current position index. + public func seeks

(f : O -> P) -> IxStore { + return IxStore(f(pos), set) + } } +/// The trivial `IxStore` always retrieves the same value at all indexes. public func trivial(x : A) -> IxStore { return IxStore(x, identity) } +/// Extracts a value from the receiver at its position index. public func extract(a : IxStore) -> A { return a.set(a.pos) } @@ -69,7 +104,7 @@ public func <^> (f : A -> B, a : IxStore) -> IxStore(f : O -> P, a : IxStore) -> IxStore { +public func <^^> (f : O -> P, a : IxStore) -> IxStore { return IxStore(f(a.pos), a.set) } @@ -77,18 +112,6 @@ public func (f : H -> I, a : IxStore) -> IxStore(a : IxStore) -> IxStore> { - return IxStore(a.pos) { IxStore($0, a.set) } -} - public func ->> (a : IxStore, f : IxStore -> B) -> IxStore { return IxStore(a.pos) { f(IxStore($0, a.set)) } } - -public func seek(a : IxStore)(x : P) -> IxStore { - return IxStore(x, a.set) -} - -public func seeks(a : IxStore)(f : O -> P) -> IxStore { - return IxStore(f(a.pos), a.set) -} From de5d3de9746c1a1b4037db800c0a1cf0e90032cd Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 14:01:49 -0600 Subject: [PATCH 06/14] Document IxMultiStore --- Focus/IxMultiStore.swift | 48 ++++++++++++++++++++++++---------------- Focus/IxStore.swift | 2 +- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Focus/IxMultiStore.swift b/Focus/IxMultiStore.swift index 7f6680b..e1cc4e7 100644 --- a/Focus/IxMultiStore.swift +++ b/Focus/IxMultiStore.swift @@ -6,12 +6,12 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - -// N.B.: This is the "inlining" of the indexed store comonad transformer -// applied to the array zipper comonad +/// The Store Comonad Transformer indexed by a position type `O` and the ArrayZipper Comonad. public struct IxMultiStore { + /// The current position of the receiver. let pos : O + /// Retrieves a zipper that focuses on functions that retrieve values at index I. let set : ArrayZipper A> public init(_ pos: O, _ set: ArrayZipper A>) { @@ -19,41 +19,64 @@ public struct IxMultiStore { self.set = set } + /// Applies a function to the retrieval of values. public func map(f : A -> B) -> IxMultiStore { return f <^> self } + /// Applies a function to the position indexes that can be focused on by the underlying zipper. public func imap

(f : O -> P) -> IxMultiStore { return f <^^> self } + /// Applies a function to the retrieval indexes of the underlying zipper. public func contramap(f : H -> I) -> IxMultiStore { return f self } - public func dup() -> IxMultiStore> { - return duplicate(self) + /// Returns an `IxStore` that retrieves an `IxStore` for every index in the receiver. + public func duplicate() -> IxMultiStore> { + return IxMultiStore>(pos, set ->> { g in { IxMultiStore($0, g) } }) } - public func extend(f : IxMultiStore -> B) -> IxMultiStore { + /// Extends the context of the store with a function that retrieves values from another store + /// indexed by a different position. + public func extend(f : IxMultiStore -> B) -> IxMultiStore { return self ->> f } + /// Extracts a zipper that focuses on all values at a given index. public func put(x : I) -> ArrayZipper { return { $0(x) } <^> set } + /// Extracts a zipper that focuses on all values at an index given by applying a function to the + /// receiver's position index. public func puts(f : O -> I) -> ArrayZipper { return put(f(pos)) } + /// Extracts the first focused value from the store at a given index. public func peek(x : I) -> A { return put(x).extract() } + /// Extracts the first focused value from the store at an index given by applying a function to + /// the receiver's position index. public func peeks(f : O -> I) -> A { return peek(f(pos)) } + + /// Returns a new `IxMultiStore` with its position index set to the given value. + public func seek

(x : P) -> IxMultiStore { + return IxMultiStore(x, set) + } + + /// Returns a new `IxMultiStore` with its position index set to the result of applying the given + /// function to the current position index. + public func seeks

(f : O -> P) -> IxMultiStore { + return IxMultiStore(f(pos), set) + } } public func extract(a : IxMultiStore) -> A { @@ -72,10 +95,6 @@ public func (f : H -> I, a : IxMultiStore) -> IxMultiSt return IxMultiStore(a.pos, { $0 • f } <^> a.set) } -public func duplicate(a : IxMultiStore) -> IxMultiStore> { - return IxMultiStore(a.pos, a.set ->> { g in { IxMultiStore($0, g) } }) -} - public func ->> (a : IxMultiStore, f : IxMultiStore -> B) -> IxMultiStore { return IxMultiStore(a.pos, a.set ->> { g in { f(IxMultiStore($0, g)) } }) } @@ -83,12 +102,3 @@ public func ->> (a : IxMultiStore, f : IxMultiStore(a : IxMultiStore) -> ArrayZipper { return { $0(a.pos) } <^> a.set } - -public func seek(a : IxMultiStore)(x : P) -> IxMultiStore { - return IxMultiStore(x, a.set) -} - -public func seeks(a : IxMultiStore)(f : O -> P) -> IxMultiStore { - return IxMultiStore(f(a.pos), a.set) -} - diff --git a/Focus/IxStore.swift b/Focus/IxStore.swift index 2d531cb..0e72d78 100644 --- a/Focus/IxStore.swift +++ b/Focus/IxStore.swift @@ -39,7 +39,7 @@ public struct IxStore { return f self } - /// Returns an `IxStore` that retrieves + /// Returns an `IxStore` that retrieves an `IxStore` for every index in the receiver. public func duplicate() -> IxStore> { return IxStore>(pos) { IxStore($0, self.set) } } From 793c2955fe9bc565e25304f8705e659eca079068 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 14:41:01 -0600 Subject: [PATCH 07/14] Document Lens --- Focus.xcodeproj/project.pbxproj | 6 +++-- Focus/Lens.swift | 48 ++++++++++++++++++++++++++++----- FocusTests/PartyExample.swift | 4 +-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/Focus.xcodeproj/project.pbxproj b/Focus.xcodeproj/project.pbxproj index 683b88c..c1bdf5e 100644 --- a/Focus.xcodeproj/project.pbxproj +++ b/Focus.xcodeproj/project.pbxproj @@ -132,13 +132,13 @@ children = ( 824B46411B460BE2009AAF49 /* ArrayZipper.swift */, 824B46471B460C1E009AAF49 /* LensOperators.swift */, + 824B46301B460B25009AAF49 /* Lens.swift */, 824B462B1B460B25009AAF49 /* Iso.swift */, + 824B46311B460B25009AAF49 /* Prism.swift */, 824B462C1B460B25009AAF49 /* IxCont.swift */, 824B462D1B460B25009AAF49 /* IxMultiStore.swift */, 824B462E1B460B25009AAF49 /* IxState.swift */, 824B462F1B460B25009AAF49 /* IxStore.swift */, - 824B46301B460B25009AAF49 /* Lens.swift */, - 824B46311B460B25009AAF49 /* Prism.swift */, 824B46401B460B28009AAF49 /* Supporting Files */, ); path = Focus; @@ -653,6 +653,7 @@ 824B46261B460AFA009AAF49 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 824B462A1B460AFA009AAF49 /* Build configuration list for PBXNativeTarget "Focus-iOSTests" */ = { isa = XCConfigurationList; @@ -661,6 +662,7 @@ 824B46281B460AFA009AAF49 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Focus/Lens.swift b/Focus/Lens.swift index 559ebf9..dc49164 100644 --- a/Focus/Lens.swift +++ b/Focus/Lens.swift @@ -6,7 +6,26 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // +/// A Lens (or Functional Reference) describes a way of focusing on the parts of a structure, +/// composing with other lenses to focus deeper into a structure, and returning new structures with +/// parts modified. In this way, a Lens can be thought of as a reference to a subpart of a +/// structure. +/// +/// A well-behaved Lens should obey the following laws: +/// +/// - You get back what you put in: +/// +/// l.get(l.set(s, b)) == b +/// +/// - Putting back what you got doesn't change anything: +/// +/// l.set(s, l.get(a)) == a +/// +/// - Setting twice is the same as setting once: +/// +/// l.set(l.set(s, a), b) == l.set(s, b) public struct Lens { + /// Gets the Indexed Costate Comonad Coalgebroid underlying the receiver. public let run : S -> IxStore public init(_ run : S -> IxStore) { @@ -17,23 +36,33 @@ public struct Lens { self.init({ v in IxStore(get(v)) { set(v, $0) } }) } + /// Creates a lens that uses a applies a modifier function to any values public init(get : S -> A, modify : (S, A -> B) -> T) { - self.init(get : get, set : { v, x in modify(v) { _ in x } }) + self.init(get: get, set: { v, x in modify(v) { _ in x } }) } + /// Composes a `Lens` with the receiver. + public func compose(l2 : Lens) -> Lens { + return self • l2 + } + + /// Runs the getter on a given structure. public func get(v : S) -> A { return run(v).pos } - public func set(v : S, _ x: B) -> T { + /// Runs the setter on a given structure and value to yield a new structure. + public func set(v : S, _ x : B) -> T { return run(v).peek(x) } - public func modify(v : S, _ f: A -> B) -> T { + /// Transform the value of the retrieved field by a function. + public func modify(v : S, _ f : A -> B) -> T { let q = run(v) return q.peek(f(q.pos)) } + /// Uses the receiver to focus in on a State Monad. public func zoom(a : IxState) -> IxState { return IxState { s1 in let q = self.run(s1) @@ -41,6 +70,15 @@ public struct Lens { return (x, q.peek(s2)) } } + + /// Creates a Lens that focuses on two structures. + public func split(right : Lens) -> Lens<(S, S_), (T, T_), (A, A_), (B, B_)> { + return Lens<(S, S_), (T, T_), (A, A_), (B, B_)> { (vl, vr) in + let q1 = self.run(vl) + let q2 = right.run(vr) + return IxStore((q1.pos, q2.pos)) { (l, r) in (q1.peek(l), q2.peek(r)) } + } + } } public func • (l1 : Lens, l2 : Lens) -> Lens { @@ -50,7 +88,3 @@ public func • (l1 : Lens, l2 : Lens) return IxStore(q2.pos) { q1.peek(q2.peek($0)) } } } - -public func comp(l1 : Lens)(l2 : Lens) -> Lens { - return l1 • l2 -} diff --git a/FocusTests/PartyExample.swift b/FocusTests/PartyExample.swift index b0881b0..5a17c55 100644 --- a/FocusTests/PartyExample.swift +++ b/FocusTests/PartyExample.swift @@ -19,11 +19,11 @@ class Party { } class func lpartyHost() -> Lens { - let getter = { (party: Party) -> User in + let getter = { (party : Party) -> User in party.host } - let setter = { (party: Party, host: User) -> Party in + let setter = { (party : Party, host : User) -> Party in Party(h: host) } From 6191b12678155d617050e765210a9f2a36aa9125 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 14:52:48 -0600 Subject: [PATCH 08/14] Add Maybe Prisms --- Focus/Prism.swift | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Focus/Prism.swift b/Focus/Prism.swift index 721a5d2..d1c568d 100644 --- a/Focus/Prism.swift +++ b/Focus/Prism.swift @@ -6,8 +6,9 @@ // Copyright (c) 2015 TypeLift. All rights reserved. // - +/// A Prism is an `Iso` where one of the functions is partial. public struct Prism { + /// public let tryGet : S -> A? public let inject : B -> T @@ -16,6 +17,11 @@ public struct Prism { self.inject = inject } + /// Composes a `Prism` with the receiver. + public func compose(i2 : Prism) -> Prism { + return self • i2 + } + public func tryModify(s : S, _ f : A -> B) -> T? { return tryGet(s).map(self.inject • f) } @@ -25,6 +31,10 @@ public func • (p1 : Prism, p2 : Prism(p1 : Prism)(p2 : Prism) -> Prism { - return p1 • p2 +public func _Some() -> Prism { + return Prism(tryGet: identity, inject: Optional.Some) +} + +public func _None() -> Prism { + return Prism(tryGet: { _ in .None }, inject: { _ in .None }) } From 041191b30ce54255388632efe342eeedcdbc679e Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 14:59:16 -0600 Subject: [PATCH 09/14] Document Prisms --- Focus/Prism.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Focus/Prism.swift b/Focus/Prism.swift index d1c568d..40e25fd 100644 --- a/Focus/Prism.swift +++ b/Focus/Prism.swift @@ -8,7 +8,6 @@ /// A Prism is an `Iso` where one of the functions is partial. public struct Prism { - /// public let tryGet : S -> A? public let inject : B -> T @@ -22,6 +21,9 @@ public struct Prism { return self • i2 } + /// Attempts to run a value of type `S` along both parts of the Prism. If `.None` is + /// encountered along the getter returns `.None`, else returns `.Some` containing the final + /// value. public func tryModify(s : S, _ f : A -> B) -> T? { return tryGet(s).map(self.inject • f) } @@ -31,10 +33,12 @@ public func • (p1 : Prism, p2 : Prism() -> Prism { return Prism(tryGet: identity, inject: Optional.Some) } +/// Provides a Prism for traversing `.None`. public func _None() -> Prism { return Prism(tryGet: { _ in .None }, inject: { _ in .None }) } From 3c6b923bbedf21ada081536cee5be4823f105e72 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 15:10:19 -0600 Subject: [PATCH 10/14] Add split and fanout --- Focus/Lens.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Focus/Lens.swift b/Focus/Lens.swift index dc49164..61a5d69 100644 --- a/Focus/Lens.swift +++ b/Focus/Lens.swift @@ -79,6 +79,15 @@ public struct Lens { return IxStore((q1.pos, q2.pos)) { (l, r) in (q1.peek(l), q2.peek(r)) } } } + + /// Creates a Lens that sends its input structure to both Lenses to focus on distinct subparts. + public func fanout(right : Lens) -> Lens { + return Lens { s in + let q1 = self.run(s) + let q2 = right.run(s) + return IxStore((q1.pos, q2.pos)) { (q1.peek($0), q2.peek($0)) } + } + } } public func • (l1 : Lens, l2 : Lens) -> Lens { From 4221cc114e6dcdb7d9e5cf8f09f6674e24fdd565 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 15:18:59 -0600 Subject: [PATCH 11/14] Document ArrayZipper --- Focus/ArrayZipper.swift | 15 +++++++++++++++ Focus/LensOperators.swift | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Focus/ArrayZipper.swift b/Focus/ArrayZipper.swift index 4daeeeb..3d537fa 100644 --- a/Focus/ArrayZipper.swift +++ b/Focus/ArrayZipper.swift @@ -11,7 +11,9 @@ public struct ArrayZipper : ArrayLiteralConvertible { typealias Element = A + /// The underlying array of values. public let values : [A] + /// The position of the cursor within the Array. public let position : Int public init(_ values : [A] = [], _ position : Int = 0) { @@ -25,17 +27,26 @@ public struct ArrayZipper : ArrayLiteralConvertible { self.values = values } + /// Creates an ArrayZipper pointing at the head of a given list of elements. public init(arrayLiteral elements : Element...) { self.init(elements, 0) } + /// Creates an `ArrayZipper` with the cursor adjusted by n in the direction of the sign of the + /// given value. public func move(n : Int = 1) -> ArrayZipper { return ArrayZipper(values, position + n) } + /// Creates an `ArrayZipper` with the cursor set to a given position value. public func moveTo(pos : Int) -> ArrayZipper { return ArrayZipper(values, pos) } + + /// Returns whether the cursor of the receiver is at the end of its underlying Array. + public var isAtEnd : Bool { + return position >= (values.count - 1) + } } extension ArrayZipper /*: Functor*/ { @@ -52,6 +63,10 @@ public func <^> (f : A -> B, xz : ArrayZipper) -> ArrayZipper { } extension ArrayZipper /*: Copointed*/ { + /// Extracts the value at the position of the receiver's cursor. + /// + /// This function is not total, but makes the guarantee that if `zipper.isAtEnd` returns false, + /// it is safe to call. public func extract() -> A { return self.values[self.position] } diff --git a/Focus/LensOperators.swift b/Focus/LensOperators.swift index c3d062c..89768de 100644 --- a/Focus/LensOperators.swift +++ b/Focus/LensOperators.swift @@ -66,4 +66,4 @@ internal func • (f : B -> C, g: A -> B) -> A -> C { return { (a : A) -> C in return f(g(a)) } -} \ No newline at end of file +} From 0a5896553bc97a6db1ed46790db5e90c7812d4d8 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 15:38:51 -0600 Subject: [PATCH 12/14] Document type parameters --- Focus/Iso.swift | 8 ++++++-- Focus/Lens.swift | 5 +++++ Focus/Prism.swift | 5 +++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Focus/Iso.swift b/Focus/Iso.swift index 4ad47d1..4c534bb 100644 --- a/Focus/Iso.swift +++ b/Focus/Iso.swift @@ -7,9 +7,13 @@ // /// Captures an isomorphism between S and A. +/// +/// :param: S The source of the Iso heading right +/// :param: T The target of the Iso heading left +/// :param: A The source of the Iso heading right +/// :param: B The target of the Iso heading left public struct Iso { - /// - public let get : S -> A + public let get : S -> A public let inject : B -> T /// Builds an Iso from a pair of inverse functions. diff --git a/Focus/Lens.swift b/Focus/Lens.swift index 61a5d69..1009a8f 100644 --- a/Focus/Lens.swift +++ b/Focus/Lens.swift @@ -24,6 +24,11 @@ /// - Setting twice is the same as setting once: /// /// l.set(l.set(s, a), b) == l.set(s, b) +/// +/// :param: S The source of the Lens +/// :param: T The modified source of the Lens +/// :param: A The target of the Lens +/// :param: B The modified target the Lens public struct Lens { /// Gets the Indexed Costate Comonad Coalgebroid underlying the receiver. public let run : S -> IxStore diff --git a/Focus/Prism.swift b/Focus/Prism.swift index 40e25fd..692a766 100644 --- a/Focus/Prism.swift +++ b/Focus/Prism.swift @@ -7,6 +7,11 @@ // /// A Prism is an `Iso` where one of the functions is partial. +/// +/// :param: S The source of the Prism +/// :param: T The modified source of the Prism +/// :param: A The possible target of the Prism +/// :param: B The modified target the Prism public struct Prism { public let tryGet : S -> A? public let inject : B -> T From 2693eed8e04df0531d757845ed3e1536ede96928 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 15:41:17 -0600 Subject: [PATCH 13/14] Write basic README --- README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bb6e4b4..e708ac9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,51 @@ # Focus -Optics for Swift +Focus is an Optics library for Swift (where Optics includes `Lens`, `Prism`s, and `Iso`s) that is +inspired by Haskell's [Lens](https://github.com/ekmett/lens) library. + +#Example + +```swift +import struct Focus.Lens +import struct Focus.IxStore + +//: A party has a host, who is a user. +final class Party { + let host : User + + init(h : User) { + host = h + } + + class func lpartyHost() -> Lens { + let getter = { (party : Party) -> User in + party.host + } + + let setter = { (party : Party, host : User) -> Party in + Party(h: host) + } + + return Lens(get: getter, set: setter) + } +} + +//: A Lens for the User's name. +extension User { + public class func luserName() -> Lens { + return Lens { user in IxStore(user.name) { User($0, user.age, user.tweets, user.attrs) } } + } +} + +//: Let's throw a party now. +let party = Party(h: User("max", 1, [], Dictionary())) + +//: A lens for a party host's name. +let hostnameLens = Party.lpartyHost() • User.luserName() + +//: Retrieve our gracious host's name. +let name = hostnameLens.get(party) // "max" + +//: Our party seems to be lacking in proper nouns. +let updatedParty = (Party.lpartyHost() • User.luserName()).set(party, "Max") +let properName = hostnameLens.get(updatedParty) // "Max" +``` \ No newline at end of file From eb16dbbba1010d6379816358b5cce86f812a1f30 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sat, 4 Jul 2015 20:16:21 -0600 Subject: [PATCH 14/14] Look, grammar --- Focus/Lens.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Focus/Lens.swift b/Focus/Lens.swift index 1009a8f..12dfa14 100644 --- a/Focus/Lens.swift +++ b/Focus/Lens.swift @@ -37,11 +37,12 @@ public struct Lens { self.run = run } + /// Creates a lens from a getter/setter pair. public init(get : S -> A, set : (S, B) -> T) { self.init({ v in IxStore(get(v)) { set(v, $0) } }) } - /// Creates a lens that uses a applies a modifier function to any values + /// Creates a lens that transforms set values by a given function before they are returned. public init(get : S -> A, modify : (S, A -> B) -> T) { self.init(get: get, set: { v, x in modify(v) { _ in x } }) }