scala lambda pattern-matching function-literal

scala - Los tipos de argumentos de una función anónima deben ser completamente conocidos.(SLS 8.5)



lambda pattern-matching (3)

Aquí es por qué quería usar una función literal y no me gustaba tener que repetir el tipo dos veces. Estaba intentando construir mi propia construcción de control para factorizar todo el código de coincidencia de opciones. Si hay demasiada sobrecarga, entonces el constructo de control no ayuda. Esto es lo que quería hacer.

//This is the control construct definition def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match { case None => noneFun case Some(y) => someFun(y) } //And this is an example of using it. def foobar( qt : Option[QualifiedType] ) = switch( qt, {reportError("SNAFU");None}, {case QualifiedType(preds, ty) => Some((emptyEqualityConstraintSet,preds)) } )

El constructo de control del conmutador se compila bien, pero el uso causó un error porque el SLS dice que donde tengo una A, debería tener un "tipo definido". Esto se debe a que este tipo de función literal (el tipo con "caso") está destinado a funciones parciales en las que el argumento podría ser legítimamente cualquier cosa. Podría argumentar mi función literal con un int y eso no sería un error de tipo, sino simplemente una cuestión de fallar todos los patrones. Así que el compilador necesita información "de arriba abajo" para saber qué tipo de letra pretendo para el parámetro de la "función expandida literal", es decir, qué poner para X en lo siguiente

{(x : X) => x match {case Some(QualifiedType(preds, ty)) => Some((emptyEqualityConstraintSet,preds)) } }

Me pregunto por qué el compilador no pudo usar el tipo de interruptor para ver que no pretendo una función parcial y luego unificar A con QualifiedType. Pero no es así.

De todos modos no se compila. Pero reemplazar A con Any elimina el error. El siguiente código realmente compila. Lo que pierdo es algún tipo de comprobación.

//This is the control construct definition def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match { case None => noneFun case Some(y) => someFun(y) } //And this is an example of using it. def foobar( qt : Option[QualifiedType] ) = switch( qt, {reportError("SNAFU");None}, {case QualifiedType(preds, ty) => Some((emptyEqualityConstraintSet,preds)) } )

Me interesaría saber (a) si se puede mejorar la definición anterior de cambio, y (b) si ya existe una función de biblioteca que hace lo que quiero.

Añadido después del comentario de Luigi

Aquí está el código final. Sí, creo que es un pliegue (catamorfismo).

def switch[A,B]( x : Option[A])(noneFun : =>B, someFun : A=>B) = x match { case None => noneFun case Some(y) => someFun(y) } def foobar( qt : Option[QualifiedType] ) : Option[(EqualityConstraintSet, TypeRelationSet)] = switch( qt )({reportError("SNAFU");None}, {case QualifiedType(preds, ty) => Some((emptyEqualityConstraintSet,preds)) } )

Gracias a Luigi.

Tengo una función literal

{case QualifiedType(preds, ty) => t.ty = ty ; Some((emptyEqualityConstraintSet,preds)) }

Lo que resulta en un mensaje de error

missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5) Expected type was: ? => Option[(Typer.this.EqualityConstraintSet, Typer.this.TypeRelationSet)]

Miré en SLS 8.5 , pero no encontré una explicación.

Si amplío la función yo mismo a

{(qt : QualifiedType) => qt match {case QualifiedType(preds, ty) => t.ty = ty ; Some((emptyEqualityConstraintSet,preds)) }}

el error desaparece

(a) ¿Por qué es esto un error?

(b) ¿Qué puedo hacer para arreglarlo?

Intenté la solución obvia, que era agregar : QualifiedType entre el patrón y =>, pero esto es un error de sintaxis.

Una cosa que noté es que el contexto hace una diferencia. Si uso la función literal como un argumento para una función declarada como que espera un QualifiedType => B , no hay error. Pero si lo uso como un argumento para una función que espera un A => B , hay un error. Espero que lo que está sucediendo aquí sea que, dado que el patrón podría aplicarse a un objeto cuyo tipo es un supertipo de QualifiedType, el compilador no está dispuesto a asignar el tipo obvio sin la seguridad de que la función no se aplicará a cualquier cosa que no sea un QualifiedType. Realmente lo que me gustaría es poder escribir {QualifiedType( preds, ty) => ...} y hacer que signifique lo mismo que Haskell''s /QualifiedType(preds,ty) -> ...


Aquí está la cita de SLS , para el resto de nosotros:

El tipo esperado de tal expresión debe ser parcialmente definido. Debe ser scala.Functionk[S1, . . . , Sk, R] scala.Functionk[S1, . . . , Sk, R] scala.Functionk[S1, . . . , Sk, R] para algunos k> 0, o scala.PartialFunction[S1, R] , donde el (los) tipo (s) de argumento scala.PartialFunction[S1, R] . . , Sk debe estar completamente determinado, pero el tipo de resultado R puede ser indeterminado.

De lo contrario, usted respondió a su pregunta.


{ case X(x) => ... } es una función parcial, pero el compilador aún no sabe cuál es su tipo de entrada, excepto que es un supertipo de X Normalmente, esto no es un problema porque si está escribiendo una función anónima, el tipo se conoce por el contexto. Pero aquí es cómo puede proporcionar el tipo:

case class Foo(x: Int) // via annotation val f: Foo => Int = { case Foo(x) => x } // use pattern matching val f = (_: Foo) match { case Foo(x) => x } // or more normally, write as a method def f(a: Foo) = a match { case Foo(x) => x } def f(a: Foo) = a.x

Como probablemente habrá notado, el uso de los literales de función / coincidencia de patrones aquí no tiene sentido. Parece que en tu caso solo necesitas un método regular:

def whatever(qt: QualifiedType) = { t.ty = qt.ty Some((emptyEqualityConstraintSet, qt.preds)) }

aunque deberías refactorizar para eliminar ese estado mutable.