# Idiomatic Swift, zipping and retroactive modeling

**URL:** <https://forums.swift.org/t/idiomatic-swift-zipping-and-retroactive-modeling/35219>\
**Category:** Using Swift\
**Created:** [April 9, 2020, 9:38am UTC](https://forums.swift.org/t/idiomatic-swift-zipping-and-retroactive-modeling/35219 "2020-04-09T09:38:36Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![Max\_Desiatov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/max_desiatov/32/20654_2.png) [@Max\_Desiatov](https://forums.swift.org/u/Max_Desiatov)\
**Post date:** [April 9, 2020, 1:00pm UTC](https://forums.swift.org/t/idiomatic-swift-zipping-and-retroactive-modeling/35219/2 "2020-04-09T13:00:17Z")

</div>

Your post highlights two different but connected issues in my opinion:

1. In my understanding of the `Result` example, this corresponds more to [`liftM`](https://hackage.haskell.org/package/base-4.12.0.0/docs/Control-Monad.html#g:7) than `zip`. I'll give an example of it in Haskell, and I'll explain in a moment why I use Haskell instead of Swift here. In Haskell `liftM` functions have these type signatures:

```haskell
liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 -> m a3 -> m r
liftM4 :: Monad m => (a1 -> a2 -> a3 -> a4 -> r) -> m a1 -> m a2 -> m a3 -> m a4 -> m r 

```

(Read `::` as Swift's `:` here and `Monad m` as Swift's `<M: Monad>` generic constraint)

The documentation string for it may sound a bit cryptic...

> Promote a function to a monad, scanning the monadic arguments from left to right. For example,

...but its purpose is easy to see with a few examples:

```swift
liftM2 (+) [0,1] [0,2] = [0,2,1,3]
liftM2 (+) (Just 1) Nothing = Nothing

```

(`Just` is equivalent to Swift's `some` and `Nothing` is equivalent to `nil`)

This is a generic (in Haskell's lingo "polymorphic") function. Basically it does the same thing you want for `Result` if I understand you correctly.

(As a sidenote, Haskell maybe could benefit from what we call "variadic generics" to avoid the proliferation of functions for each number of arguments here 😜)

Note that `liftM` family of functions is generic over the type of a "container" (called `Monad` here), so the same `liftM2` function definition will work for any "container" that defines a "conformance" to `Monad`, be it an array, a set, a result type or whatever. (I put "conformance" in quotes here because in Haskell it is called "a type class instance" where a "type class" is roughly what we call a "protocol" in Swift).

This feature is called ["higher-kinded types"](https://forums.swift.org/t/higher-kinded-types-monads-functors-etc/4691) and is not available in Swift, unfortunately. I personally don't see a compelling answer for why it's not on the roadmap. Thus we're doomed to ~~reinvent the wheel~~ reimplement the same `flatMap` function (or the aforementioned `liftM` function for that matter) over and over again for `Result`, `Publisher`, collection types etc, even though all reimplementations of it work in the same way and we're basically copy-pasting it, substituting the container type for every case. The `flatMap` function in Swift is generic, but not generic enough 🙂

One argument against higher-kinded types feature in Swift was that it's "too complex". Although one could question how multiple copies of the same algorithm are less complex than a single implementation we'd have with higher-kinded types in Swift. Let's imagine how it would look, I'll call it `Liftable` to make it sound more "approachable" than `Monad` 😄

```swift
protocol Liftable {
 // a few requirements here I'll leave out, 
 // mostly would be a translation of Haskell's `Monad` type class
}

extension Liftable {
  func liftM2<T1, T2, R>(
    _ first: Self<T1>, 
    _ second: Self<T2>, 
    lifter: (T1, T2) -> R
  ) -> Self<R> {
    // generic implementation for any `Liftable` type
  }

extension Result: Liftable {}
extension Array: Liftable {}
extension Publisher: Liftable {}
// and so on...

```

What Swift doesn't allow here is the `Self<T>` construct, you can probably find some alternative syntax in numerous pitches of higher-kinded types here on Swift Forums.

1. With your second example I would prefer a free function myself, especially because the `CopyableWithModification` protocol doesn't have any requirements and `with` function, in principle, can be applied to any type, no generic constraints needed. The downside of free functions is that they can pollute the global namespace, especially if you have many of them that doing the same thing but requiring different generic constraints. This is actually a corollary of the point "1" above, if Swift supported higher-kinded types from the start, wouldn't we be fine with a single `flatMap` in the global namespace instead of the current situation where every `flatMap` variation is namespaced as a member on its corresponding type? I don't know, maybe it's still a matter of preference and even if higher-kinded types are ever added to Swift it would probably be too late to change the convention.

Hope this answers your questions, but I'd be happy to clarify whatever sounds too convoluted in my post 🙂

---

_[View the full topic](https://forums.swift.org/t/idiomatic-swift-zipping-and-retroactive-modeling/35219)._
