2012-07-16 35 views
5

Estoy experimentando con scalaz. Traté de escribir código en código aplicativo. Escribí un código como este:Más sintaxis de aplicación tipo haskell en scalaz

val max: Option[Int] = (a |@| b) { math.max(_, _) } 

No me gustó mucho este código. Me gustaría hacer un código que esté más cerca del estilo Haskell, algo como esto:

val max: Option[Int] = { math.max(_, _) } <$> a <*> b 

Esto es posible. ¿Y por qué Scalaz no lo implementó de esta manera?

+0

Solo por curiosidad: ¿Qué es lo que no te gusta? Encuentro la versión "scalaz" más limpia para el (mi) ojo ... – Jan

+1

En Haskell, simplemente escribirías 'max <$> a <*> b', que personalmente prefiero a cualquiera de las versiones de Scalaz. –

+0

@TravisBrown ¿cómo lo escribirías para más de dos args? "diversión <$> a <*> b <*> c"? – Jan

Respuesta

7

La inferencia de tipo de Scala es mucho más limitada que en Haskell (sobrecarga de identificador, que viene con la JVM como una de las razones). Las inferencias fluyen de izquierda a derecha, y el tipo de argumentos de una función se puede deducir del contexto anterior (si en el lugar de la definición se espera una función con arg tipo A), pero no de cómo se usan en el definición. La sintaxis de Scalaz hace que los tipos de argumentos estén disponibles. Invertirlo la mayoría de las veces lo obligaría a escribir los tipos de argumentos de la función, p.

{math.max(_: Int, _: Int) } <$> a <*> b 
+0

Sin embargo, hay muchas veces en que trato con un valor de función existente cuyo tipo completo ya se conoce. En ese caso, realmente me gustaría tener la sintaxis 'f <$> a <*> b'. Dado que ya tenemos la sintaxis del generador de aplicaciones hacia atrás '(a | @ | b) {math.max (_, _)}' para el caso de la función anónima, no veo por qué no podemos tener el estilo natural de Haskell sintaxis para el caso del valor de la función. –

4

Usted puede traducir la versión Haskell directamente en Scala, si usted está dispuesto a ser un poco más detallado:

import scalaz._, Scalaz._ 

val a = Option(1) 
val b = Option(2) 
val f: Int => Int => Int = x => math.max(x, _) 

val c = b <*> (a map f) 

O, como una sola línea:

val c = 2.some <*> 1.some.map(x => math.max(x, _: Int)) 

O:

val c = 2.some <*> (1.some map (math.max _).curried) 

El orden se invierte porque se trata de llamadas a métodos en lugar de operadores infix, pero es esencialmente lo mismo que max <$> a <*> b: asignamos la función sobre el primer elemento y luego aplicamos el resultado al segundo.