Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optional traversal #28

Open
marcprux opened this issue Apr 29, 2016 · 6 comments
Open

Optional traversal #28

marcprux opened this issue Apr 29, 2016 · 6 comments

Comments

@marcprux
Copy link

Is there no way to lens through an optional? I've tried with Party.lpartyCaterer() • User.userName and Party.lpartyCaterer() • _Some • User.userName, to no avail.

// A party has a host, an optional caterer and an array of guests
class Party {
    var host : User
    var caterer : User?
    var guests : [User]

    init(h : User, c : User? = nil, g : [User] = []) {
        host = h
        caterer = c
        guests = g
    }

    class func lpartyHost() -> Lens<Party, Party, User, User> {
        let getter = { (party : Party) -> User in party.host }
        let setter = { (party : Party, host : User) -> Party in Party(h: host, c: party.caterer, g: party.guests) }
        return Lens(get: getter, set: setter)
    }

    class func lpartyCaterer() -> Lens<Party, Party, User?, User?> {
        let getter = { (party : Party) -> User? in party.caterer }
        let setter = { (party : Party, caterer : User?) -> Party in Party(h: party.host, c: caterer, g: party.guests) }
        return Lens(get: getter, set: setter)
    }

    class func lpartyGuests() -> Lens<Party, Party, [User], [User]> {
        let getter = { (party : Party) -> [User] in party.guests }
        let setter = { (party : Party, guests : [User]) -> Party in Party(h: party.host, c: party.caterer, g: guests) }
        return Lens(get: getter, set: setter)
    }
}

class PartySpec : XCTestCase {
    func testLens() {
        let party = Party(h: User("max", 1, [], "one"))
        let hostnameLens = Party.lpartyHost()  User.userName

        XCTAssert(hostnameLens.get(party) == "max")

        let updatedParty: Party = (Party.lpartyHost()  User.userName).set(party, "Max")
        XCTAssert(hostnameLens.get(updatedParty) == "Max")

        let catererLens = Party.lpartyCaterer()  User.userName

        let cateredParty: Party = (Party.lpartyCaterer()  User.userName).set(party, "Marc")
        XCTAssert(catererLens.get(updatedParty) == "Marc")

    }
}
@CodaFi
Copy link
Member

CodaFi commented Apr 29, 2016

A Lens is not a Prism (in fact, they are sort of categorically dual), of which _Some() must be because T? -> T is, by its very nature, a partial operation. You need a prism hierarchy for this, not a lens hierarchy.

@CodaFi
Copy link
Member

CodaFi commented Apr 29, 2016

Or you could (though I definitely don't recommend this) define the type of a forcing lens for Optionals. Maybe call it _UnsafeSome, then use that as your intermediary. Otherwise, because Swift doesn't let us express the variance of types, or treat this as a valid coercion, you have to rewrite the hierarchy.

@marcprux
Copy link
Author

I'd expect a Lens composed with a Prism to be a Focus.Optional, but it looks like it isn't implemented: #4 😞

Is Optional unimplemented due to Swift language shortcomings, or just because no one has gotten around to it yet?

@CodaFi
Copy link
Member

CodaFi commented Apr 30, 2016

Little of one, little of the other. A lot of the reason we haven't implemented things is because it's just not worth it yet. A lot of the power of the Lens library is things generalize in a thousand little ways where in Swift you're lucky to get one.

@marcprux
Copy link
Author

Do you foresee any of the planned improvements in Swift 3 making the implementation more worthwhile?

@CodaFi
Copy link
Member

CodaFi commented Apr 30, 2016

Nope. Needs HKTs, which also necessitates a huge number of proposals that would fundamentally alter the language.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants