Home > OS >  How can I define `unlines` function generically?
How can I define `unlines` function generically?

Time:01-22

I would like to define a unlines function which works which any Sequence whose elements conform to the StringProtocol; this is my attempt:

func unlines<S: StringProtocol>(_ xs: Sequence<S>) -> S {
    return xs.joined(separator: "\n")
}

Error: Use of protocol 'Sequence' as a type must be written 'any Sequence'

A version defined for a concrete type does work:

func unlines(_ xs: [String]) -> String {
    return xs.joined(separator: "\n")
}

but can only be applied with list of String.

How can I develop a general definition ?

EDIT:

For example, I would like to apply it to the following value:

["Hello", "World"].lazy.map { $0.lowercased() }

CodePudding user response:

joined returns a String so you need to change the return type and use any Sequence

func unlines<S: StringProtocol>(_ xs: any Sequence<S>) -> String {
    return xs.joined(separator: "\n")
}

This then works both with String and Substring

String example:

let result = unlines(["A", "B", "C"])

Substring example:

let result = unlines("A-B-C".split(separator: "-"))

both returns

A
B
C

CodePudding user response:

In Swift, you'd typically use a protocol extension to define instance functions that should operate on an instance, rather than using free functions that take a first argument.

Here's how that might work:

extension Sequence where Element: StringProtocol {
    // FIXME: This is a pretty Haskelly, non-Swifty
    func unlines() -> String {
        joined(separator: "\n")
    }
}

let input = ["Hello", "World"]
    .lazy
    .map { $0.lowercased() }
    .unlines()

print(input)
// Prints:
// hello
// world
  • Related