suzuki sport programación precio lenguaje apple swift

sport - swift apple



¿Cómo podemos crear una extensión de matriz genérica que sume los tipos de números en Swift? (7)

A partir de Swift 2 es posible hacerlo utilizando extensiones de protocolo. (Consulte El lenguaje de programación Swift: Protocolos para obtener más información).

En primer lugar, el protocolo Addable :

protocol Addable: IntegerLiteralConvertible { func + (lhs: Self, rhs: Self) -> Self } extension Int : Addable {} extension Double: Addable {} // ...

A continuación, extienda SequenceType para agregar secuencias de elementos Addable :

extension SequenceType where Generator.Element: Addable { var sum: Generator.Element { return reduce(0, combine: +) } }

Uso:

let ints = [0, 1, 2, 3] print(ints.sum) // Prints: "6" let doubles = [0.0, 1.0, 2.0, 3.0] print(doubles.sum) // Prints: "6.0"

Swift te permite crear una extensión de Array que suma a Integer con:

extension Array { func sum() -> Int { return self.map { $0 as Int }.reduce(0) { $0 + $1 } } }

Que ahora se puede usar para sumar Int[] como:

[1,2,3].sum() //6

Pero, ¿cómo podemos hacer una versión genérica que admita la suma de otros tipos de números como Double[] también?

[1.1,2.1,3.1].sum() //fails

Esta pregunta NO es cómo sumar números , sino cómo crear una Extensión de Array genérica para hacerlo.

Acercarse

Esto es lo más cercano que he podido conseguir si ayuda a alguien a acercarse a la solución:

Puede crear un protocolo que cumpla con lo que necesitamos hacer, es decir:

protocol Addable { func +(lhs: Self, rhs: Self) -> Self init() }

Luego extienda cada uno de los tipos que queremos que cumplan con el protocolo anterior:

extension Int : Addable { } extension Double : Addable { }

Y luego agrega una extensión con esa restricción:

extension Array { func sum<T : Addable>(min:T) -> T { return self.map { $0 as T }.reduce(min) { $0 + $1 } } }

Que ahora se puede usar contra los números que hemos extendido para admitir el protocolo, es decir:

[1,2,3].sum(0) //6 [1.1,2.1,3.1].sum(0.0) //6.3

Desafortunadamente, no he podido hacer que funcione sin tener que proporcionar un argumento, es decir:

func sum<T : Addable>(x:T...) -> T? { return self.map { $0 as T }.reduce(T()) { $0 + $1 } }

El método modificado todavía funciona con 1 argumento:

[1,2,3].sum(0) //6

Pero no puede resolver el método cuando lo llama sin argumentos, es decir:

[1,2,3].sum() //Could not find member ''sum''

Agregar Integer a la firma del método tampoco ayuda con la resolución del método:

func sum<T where T : Integer, T: Addable>() -> T? { return self.map { $0 as T }.reduce(T()) { $0 + $1 } }

Pero espero que esto ayude a otros a acercarse a la solución.

Algo de progreso

Desde la respuesta de @GabrielePetronella, parece que podemos llamar al método anterior si especificamos explícitamente el tipo en el sitio de la llamada como:

let i:Int = [1,2,3].sum() let d:Double = [1.1,2.2,3.3].sum()


Aquí hay una implementación tonta:

extension Array { func sum(arr:Array<Int>) -> Int { return arr.reduce(0, {(e1:Int, e2:Int) -> Int in return e1 + e2}) } func sum(arr:Array<Double>) -> Double { return arr.reduce(0, {(e1:Double, e2:Double) -> Double in return e1 + e2}) } }

Es tonto porque tienes que decir arr.sum(arr) . En otras palabras, no está encapsulado; es una sum función "gratuita" que simplemente se esconde dentro de Array. Por lo tanto, no pude resolver el problema que realmente intentas resolver.


Creo que encontré una forma razonable de hacerlo, tomando prestadas algunas ideas de scalaz y comenzando desde la implementación propuesta. Básicamente, lo que queremos es tener clases de tipos que representen monoides.

En otras palabras, necesitamos:

  • una función asociativa
  • un valor de identidad (es decir, un cero)

Aquí hay una solución propuesta, que funciona en torno a las limitaciones del sistema de tipo swift

En primer lugar, nuestra amable Addable tipos Addable .

protocol Addable { class func add(lhs: Self, _ rhs: Self) -> Self class func zero() -> Self }

Ahora hagamos que Int implemente.

extension Int: Addable { static func add(lhs: Int, _ rhs: Int) -> Int { return lhs + rhs } static func zero() -> Int { return 0 } }

Hasta ahora tan bueno. Ahora tenemos todas las piezas que necesitamos para construir una función sum suma genérica:

extension Array { func sum<T : Addable>() -> T { return self.map { $0 as T }.reduce(T.zero()) { T.add($0, $1) } } }

Vamos a probarlo

let result: Int = [1,2,3].sum() // 6, yay!

Debido a las limitaciones del sistema de tipos, debe convertir explícitamente el tipo de resultado, ya que el compilador no puede calcular por sí mismo que Addable resuelve en Int .

Así que no puedes simplemente hacer:

let result = [1,2,3].sum()

Creo que es un inconveniente soportable de este enfoque.

Por supuesto, esto es completamente genérico y se puede usar en cualquier clase, para cualquier tipo de monoide. La razón por la que no estoy usando el operador predeterminado + , sino que estoy definiendo una función de add , es que esto permite que cualquier tipo implemente la Addable tipos Addable. Si usa + , entonces un tipo que no tiene un operador + definido, entonces necesita implementar dicho operador en el ámbito global, lo que me disgusta.

De todos modos, así es como funcionaría si necesitas, por ejemplo, hacer que Int y String ''multiplicables'', dado que * está definido para Int pero no para `String.

protocol Multipliable { func *(lhs: Self, rhs: Self) -> Self class func m_zero() -> Self } func *(lhs: String, rhs: String) -> String { return rhs + lhs } extension String: Multipliable { static func m_zero() -> String { return "" } } extension Int: Multipliable { static func m_zero() -> Int { return 1 } } extension Array { func mult<T: Multipliable>() -> T { return self.map { $0 as T }.reduce(T.m_zero()) { $0 * $1 } } } let y: String = ["hello", " ", "world"].mult()

Ahora la matriz de String puede usar el método mult para realizar una concatenación inversa (solo un ejemplo tonto), y la implementación usa el operador * , recién definido para String , mientras que Int sigue usando su operador habitual * y solo necesitamos definir un cero para el monoide.

Para la limpieza del código, prefiero tener toda la implementación de typeclass para vivir en el alcance de la extension , pero creo que es una cuestión de gusto.


Desde mi entendimiento de la gramática rápida, un identificador de tipo no puede usarse con parámetros genéricos, solo un argumento genérico. Por lo tanto, la declaración de extensión solo se puede utilizar con un tipo concreto.


En Swift 2, puedes resolverlo así:

Definir el monoide para añadir como protocolo.

protocol Addable { init() func +(lhs: Self, rhs: Self) -> Self static var zero: Self { get } } extension Addable { static var zero: Self { return Self() } }

Además de otras soluciones, esto define explícitamente el elemento cero utilizando el inicializador estándar.

Luego declara Int y Double como Addable:

extension Int: Addable {} extension Double: Addable {}

Ahora puede definir un método sum () para todos los Arrays que almacenan elementos Addable:

extension Array where Element: Addable { func sum() -> Element { return self.reduce(Element.zero, combine: +) } }


Es factible según las respuestas anteriores en Swift 1.x con un mínimo esfuerzo:

import Foundation protocol Addable { func +(lhs: Self, rhs: Self) -> Self init(_: Int) init() } extension Int : Addable {} extension Int8 : Addable {} extension Int16 : Addable {} extension Int32 : Addable {} extension Int64 : Addable {} extension UInt : Addable {} extension UInt8 : Addable {} extension UInt16 : Addable {} extension UInt32 : Addable {} extension UInt64 : Addable {} extension Double : Addable {} extension Float : Addable {} extension Float80 : Addable {} // NSNumber is a messy, fat class for ObjC to box non-NSObject values // Bit is weird extension Array { func sum<T : Addable>(min: T = T(0)) -> T { return map { $0 as! T }.reduce(min) { $0 + $1 } } }

Y aquí: https://gist.github.com/46c1d4d1e9425f730b08

Swift 2, como se usa en otros lugares, planea mejoras importantes, incluido el manejo de excepciones, promesas y una mejor metaprogramación genérica.