I'm new to Swift, and I'd like to know if the language has some equivalent to Python's decorator pattern.For example:
import functools
def announce(func):
"""Print a function's arguments and return value as it's called."""
#functools.wraps(func)
def announced_func(*args, **kwargs):
rv = func(*args, **kwargs)
print('In: {0}, {1}'.format(args, kwargs))
print('Out: {}'.format(rv))
return rv
return announced_func
#announce # add = announce(add)
def add(a, b):
return a + b
add(2, 5)
# In: (2, 5), {}
# Out: 7
# 7
Perhaps I just haven't found it yet, but Swift doesn't seem to have a way to forward arbitrary arguments to functions or to preserve a wrapped function's information (as functools.wraps does).Is there an equivalent, or is the pattern not meant to be used in Swift?
Example above updated for Swift 5.1+
#propertyWrapper
struct Announced<T, U> {
private let announcedFunction: (T) -> U
var wrappedValue: (T) -> U { announcedFunction }
init(wrappedValue: #escaping (T) -> U) {
announcedFunction = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
struct Test {
#Announced static var add: ((Int, Int)) -> Int = { $0.0 + $0.1 }
#Announced static var multiply: ((Int, Int)) -> Int = { $0.0 * $0.1 }
#Announced static var length : (String) -> Int = { (str: String) in str.count }
#Announced static var greet: (String) -> String = { "Hello, \($0)" }
}
Test.add((2, 5)) // In: (2, 5)\n Out: 7
Test.multiply((2, 5)) // In: (2, 5)\n Out: 10
Test.length("Hello world!") // In: Hello world!\n Out: 12
Test.greet("Paul") // In: Paul\n Out: Hello, Paul
[Edit] Actually, it can be simplified:
#propertyWrapper
struct Announced<T, U> {
let wrappedValue: (T) -> U
init(wrappedValue: #escaping (T) -> U) {
self.wrappedValue = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
You can use this:
func decorate<T, U>(_ function: #escaping (T) -> U, decoration: #escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: (Int, Int) -> Int = decorate(+) { args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add(2, 5) // In: (2, 5)\nOut: 7
Or announce as function instead of closure, allowing reuse:
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let add: (Int, Int) -> Int = decorate(+, decoration: announce)
add(2, 5) // In: (2, 5)\nOut: 7
let length = decorate({(str: String) in str.characters.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
Example above updated for Swift 4+. Requires that the parameters are formally tuples. I also added one more example, that decorates a string.
func decorate<T, U>(_ function: #escaping (T) -> U,
decoration: #escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: ((Int, Int)) -> Int = decorate(+) {args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add((2, 5)) // In: (2, 5)\nOut: 7
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let multiply: ((Int, Int)) -> Int = decorate(*, decoration: announce)
multiply((2, 5)) // In: (2, 5)\nOut: 10
let length = decorate( { (str: String) in str.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
let greet: ((String)) -> String = decorate( {"Hello, \($0)" }, decoration: announce)
greet(("Paul")) // In: Paul\nOut: Hello, Paul
Related
I am studying the swift programming language.
Now I'm looking at how opaque types works.
Why does it occur error: type of expression is ambiguous without more context? (Swift 5.1)
protocol NumericExpression {
associatedtype TNumeric: Numeric
var value: TNumeric { get }
}
struct Expression {
static func sum<TA: NumericExpression, TB: NumericExpression>(_ a: TA,_ b: TB) -> some NumericExpression
where TA.TNumeric == TB.TNumeric {
return NumericExpressionSum(a: a, b: b)
}
static func multi<TA: NumericExpression, TB: NumericExpression>(_ a: TA, _ b: TB) -> some NumericExpression
where TA.TNumeric == TB.TNumeric {
return NumericExpressionMulti(a: a, b: b)
}
}
extension Int: NumericExpression {
var value: Self {
return self
}
}
struct NumericExpressionSum<TA: NumericExpression, TB: NumericExpression>: NumericExpression
where TA.TNumeric == TB.TNumeric {
let a: TA
let b: TB
var value: TA.TNumeric { a.value + b.value }
}
struct NumericExpressionMulti<TA: NumericExpression, TB: NumericExpression>: NumericExpression
where TA.TNumeric == TB.TNumeric {
let a: TA
let b: TB
var value: TA.TNumeric { a.value * b.value }
}
No compile error.
Sample code with compile error:
var s1 = Expression.sum(1, 2)
var s2 = Expression.sum(2, 3)
var m1 = Expression.multi(s1, s2)
var m2 = Expression.multi(3, 4)
print(m1.value) // 15
print(m2.value) // 12
print(type(of: m1)) // NumericExpressionMulti<NumericExpressionSum<Int, Int>, NumericExpressionSum<Int, Int>>
print(type(of: m2)) // NumericExpressionMulti<Int, Int>
print(type(of: m1).TNumeric) // Int
print(type(of: m2).TNumeric) // Int
let m3 = Expression.multi(m1, m2) //Error: type of expression is ambiguous without more context
Does this work for swift 5.5?
Thanks!
I'm trying to build a generic memoization function
func memoize<Arg: Hashable, Ret>(_ fn: #escaping ((Arg) -> Ret)) -> ((Arg) -> Ret) {
var cache: [Arg:Ret] = [:]
func inner (x: Arg) -> Ret {
let ret = cache[x, default: fn(x)]
cache[x] = ret
return ret
}
return inner
}
But I am unable to define my function as a closure for some reason
struct Foo: Hashable {
let a: String
let b: String
}
let foo = memoize(
(x: Foo) -> String in {
print("miss")
return x.a
}
)
Cannot convert value of type '((Foo) -> String).Type' to expected argument type '(Arg) -> Ret'
Generic parameter 'Arg' could not be inferred
why is that?
Your closure syntax is incorrect. The signature part goes inside of the { } (See Closure Expression Syntax):
let foo = memoize(
{ (x: Foo) -> String in
print("miss")
return x.a
}
)
You can also omit the () (known as a trailing closure), which is more idiomatic:
let foo = memoize {
(x: Foo) -> String in
print("miss")
return x.a
}
In the below example, why is the foo(f) call ambiguous?
I understand that the second overload could also apply with P == (),
but why isn't the first one considered more specialized,
and therefore a better match?
func foo<R>(_ f: () -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
let f: () -> Int = { 42 }
foo(f) // "Ambiguous use of 'foo'"
I'd say your problem is that you don't explicitely tell the compiler that P == ()
try the following code in a playground :
Void.self == (Void).self // true
Void() == () // true
(Void)() == () // true
(Void) == () // Cannot convert value of type '(Void).Type' to expected argument type '()'
Foo<Int>.self == (() -> Int).self // false
(() -> Int).self == ((Void) -> Int).self // false
Foo<Int>.self == ((Void) -> Int).self // true
Since (Void) cannot be converted to (), I guess the compiler can't understand that foo<R>(_ f: () -> R) is actually a specialization of foo<P, R>(_ f: (P) -> R).
I suggest you create generic type aliases for your function types to help the compiler understand what you're doing eg. :
typealias Bar<P, R> = (P) -> R
typealias Foo<R> = Bar<Void, R>
Now you can can define your function like that :
func foo<R>(_ f: Foo<R>) { print("r") } // Note that this does not trigger a warning.
func foo<P, R>(_ f: Bar<P, R>) { print("pr") }
and then use them with any closure you want :
let f: () -> Int = { 42 }
foo(f) // prints "r"
let b: (Int) -> Int = { $0 }
foo(b) // prints "pr"
let s: (String) -> Double = { _ in 0.0 }
foo(s) // prints "pr"
But you can actually just write :
func foo<R>(_ f: (()) -> R) { print("r") }
func foo<P, R>(_ f: (P) -> R) { print("pr") }
or even :
func foo<R>(_ f: (Void) -> R) { print("r") } // triggers warning :
// When calling this function in Swift 4 or later, you must pass a '()' tuple; did you mean for the input type to be '()'?
func foo<P, R>(_ f: (P) -> R) { print("pr") }
and you get the same results.
func function1(arg: Int) -> Int { return arg }
func function2<T>(arg: T) -> T { return arg }
let f1 = function1 // No problem
let f2 = function2<Int> // Cannot explicitly specialize a generic function
A current short coming of the language?
You can let Swift infer the specialization of function2 by the explicit type annotation of f2:
let f2: (Int) -> Int = function2
Alternatively, use an intermediate specializer function which supplies the explicit type annotation
func specialize1Dmap<T>(_ f: #escaping (T) -> T, as _: T.Type) -> (T) -> T { return f }
let f2int = specialize1Dmap(function2, as: Int.self)
let f2str = specialize1Dmap(function2, as: String.self)
I am attempting to implement Church Numerals in Swift 3. Currently, I have:
func numToChurch(n: Int) -> ((Int) -> Int) -> Int {
return { (f: (Int) -> Int) -> (Int) -> Int in
return { (x : Int) -> Int in
return f(numToChurch(n: n - 1)(f)(x))
}
}
}
func churchToNum(f: ((Int) -> Int) -> (Int)-> Int) -> Int {
return f({ (i : Int) -> Int in
return i + 1
})(0)
}
At this line in my function numToChurch:
return f(numToChurch(n: n - 1)(f)(x))
I keep getting a compile-time error that "Closure of non-escaping parameter 'f' may allow it to escape". As a quick-fix, I accepted the recommended changes to include #escaping:
func numToChurch(n: Int) -> ((Int) -> Int) -> Int {
return { (f: #escaping (Int) -> Int) -> (Int) -> Int in
return { (x : Int) -> Int in
return f(numToChurch(n: n - 1)(f)(x))
}
}
}
But even after making the changes, I keep getting told the same error and it recommends adding another #escaping after "f:". I understand that this has to do with marking function parameters as #escaping to tell the compiler that the parameters can be stored or captured for functional programming. But I don't understand why I keep getting this error.
Original non-escaping question resolved
Help with understanding church encoding in Swift cont:
func zero(_f: Int) -> (Int) -> Int {
return { (x: Int) -> Int in
return x
}
}
func one(f: #escaping (Int) -> Int) -> (Int) -> Int {
return { (x: Int) in
return f(x)
}
}
func two(f: #escaping (Int) -> Int) -> (Int) -> Int {
return { (x: Int) in
return f(f(x))
}
}
func succ(_ f: Int) -> (#escaping (Int) -> Int) -> (Int) -> Int {
return { (f : #escaping ((Int) -> Int)) -> Int in
return { (x : Int) -> Int in
return f(n(f)(x))
}
}
}
func sum(m: #escaping ((Int) -> (Int) -> Int)) -> ((Int) -> (Int) -> Int) -> (Int) -> (Int) -> Int {
return { (n: #escaping ((Int) -> Int)) -> (Int) -> (Int) -> Int in
return { (f: Int) -> (Int) -> Int in
return { (x: Int) -> Int in
return m(f)(n(f)(x))
}
}
}
You're using currying for multi-parameter functions. That isn't a very natural way to express things in Swift and it's making things complicated. (Swift is not a functional programming language.)
As your linked article says, "All Church numerals are functions that take two parameters." So do that. Make it a two parameter function.
typealias Church = (_ f: ((Int) -> Int), _ x: Int) -> Int
This is a function that takes two parameters, a function and its argument.
Now you want to wrap the argument in the function N times:
// You could probably write this iteratively, but it is pretty elegant recursively
func numToChurch(_ n: Int) -> Church {
// Church(0) does not apply the function
guard n > 0 else { return { (_, n) in n } }
// Otherwise, recursively apply the function
return { (f, x) in
numToChurch(n - 1)(f, f(x))
}
}
And getting back is just applying the function:
func churchToNum(_ church: Church) -> Int {
return church({$0 + 1}, 0)
}
Just building up on this, you can curry it (and I think I'm just saying what #kennytm has also answered). Currying is just slightly more complicated in Swift:
typealias Church = (#escaping (Int) -> Int) -> (Int) -> Int
func numToChurch(_ n: Int) -> Church {
// Church(0) does not apply the function
guard n > 0 else { return { _ in { n in n } } }
return { f in { x in
numToChurch(n - 1)(f)(f(x))
}
}
}
func churchToNum(_ church: Church) -> Int {
return church({$0 + 1})(0)
}
There's a very reasonable question: "Why do I need #escaping in the second case, but not in the first?" The answer is that when you pass the function in a tuple, you've already escaped it (by storing it in another data structure), so you don't need to mark it #escaping again.
To your further questions, using a typealias dramatically simplifies this problem and helps you think through your types much more clearly.
So what are the parameters of zero? Nothing. It's a constant. So what should its signature be?
func zero() -> Church
How do we implement it? We apply f zero times
func zero() -> Church {
return { f in { x in
x
} }
}
One and two are nearly identical:
func one() -> Church {
return { f in { x in
f(x)
} }
}
func two() -> Church {
return { f in { x in
f(f(x))
} }
}
What is the signature of succ? It takes a Church and returns a Church:
func succ(_ n: #escaping Church) -> Church {
Because this is Swift, we need a little nudge by adding #escaping and _ to make things more natural. (Swift is not a functional language; it decomposes problems differently. Composing functions is not its natural state, so the over-abundence of syntax should not shock us.) How to implement? Apply one more f to n:
func succ(_ n: #escaping Church) -> Church {
return { f in { x in
let nValue = n(f)(x)
return f(nValue)
} }
}
And again, what is the nature of sum? Well, we're in a currying mood, so that means it's a function that takes a Church and returns a function that takes a Church and returns a Church.
func sum(_ n: #escaping Church) -> (#escaping Church) -> Church
Again, a little extra syntax is needed because Swift. (And as above I've added an extra let binding just to make the pieces a little more clear.)
func sum(_ n: #escaping Church) -> (#escaping Church) -> Church {
return { m in { f in { x in
let nValue = n(f)(x)
return m(f)(nValue)
} } }
}
The deep lesson here is the power of the Church typealias. When you try to think of Church numbers as "functions that blah blah blah" you quickly get lost in the curry and syntax. Instead, abstract them to be "Church numbers" and just think about what every function should take and return. Remember that a Church number is always a function that takes an Int and returns an Int. It never grows or shrinks from that no matter how many times it's been nested.
It's worth taking this example in a couple of other directions because we can play out some deeper ideas of FP and also how Swift should really be written (which are not the same....)
First, writing Church numbers in pointed style is...inelegant. It just feels bad. Church numbers are defined in terms of functional composition, not application, so they should be written in a point-free style IMO. Basically, anywhere you see { f in { x in ...} }, that's just ugly and over-syntaxed. So we want functional composition. OK, we can dig into some experimental stdlib features and get that
infix operator ∘ : CompositionPrecedence
precedencegroup CompositionPrecedence {
associativity: left
higherThan: TernaryPrecedence
}
public func ∘<T, U, V>(g: #escaping (U) -> V, f: #escaping (T) -> U) -> ((T) -> V) {
return { g(f($0)) }
}
Now, what does that do for us?
func numToChurch(_ n: Int) -> Church {
// Church(0) does not apply the function
guard n > 0 else { return zero() }
return { f in f ∘ numToChurch(n - 1)(f) }
}
func succ(_ n: #escaping Church) -> Church {
return { f in f ∘ n(f) }
}
func sum(_ n: #escaping Church) -> (#escaping Church) -> Church {
return { m in { f in
n(f) ∘ m(f)
} }
}
So we don't need to talk about x anymore. And we capture the essence of Church numbers much more powerfully, IMO. Summing them is equivalent to functional composition.
But all that said, IMO this is not great Swift. Swift wants structure and methods, not functions. It definitely doesn't want a top-level function called zero(). That's horrible Swift. So how do we implement Church numbers in Swift? By lifting into a type.
struct Church {
typealias F = (#escaping (Int) -> Int) -> (Int) -> Int
let applying: F
static let zero: Church = Church{ _ in { $0 } }
func successor() -> Church {
return Church{ f in f ∘ self.applying(f) }
}
static func + (lhs: Church, rhs: Church) -> Church {
return Church{ f in lhs.applying(f) ∘ rhs.applying(f) }
}
}
extension Church {
init(_ n: Int) {
if n <= 0 { self = .zero }
else { applying = { f in f ∘ Church(n - 1).applying(f) } }
}
}
extension Int {
init(_ church: Church) {
self = church.applying{ $0 + 1 }(0)
}
}
Int(Church(3) + Church(7).successor() + Church.zero) // 11
#escaping is part of the argument type, so you need to do it like:
func numToChurch(n: Int) -> (#escaping (Int) -> Int) -> (Int) -> Int {
// ^~~~~~~~~
Complete, working code:
func numToChurch(n: Int) -> (#escaping (Int) -> Int) -> (Int) -> Int {
// ^~~~~~~~~ ^~~~~~
return { (f: #escaping (Int) -> Int) -> (Int) -> Int in
// ^~~~~~~~~
if n == 0 {
return { x in x }
} else {
return { (x : Int) -> Int in
return f(numToChurch(n: n - 1)(f)(x))
}
}
}
}
func churchToNum(f: (#escaping (Int) -> Int) -> (Int) -> Int) -> Int {
// ^~~~~~~~~
return f({ (i : Int) -> Int in
return i + 1
})(0)
}
let church = numToChurch(n: 4)
let num = churchToNum(f: church)
Note:
Your return type of numToChurch is wrong even without the #escaping part. You are missing a -> Int.
I have added the base n == 0 case in numToChurch, otherwise it will be an infinite recursion.
Since the result of numToChurch has an escaping closure, the same annotation needs to be added to that of churchToNum as well.