2012-07-16 12 views
5

Eksperymentuję z scalazem. Próbowałem pisać kod w kodzie aplikacyjnym. Napisałem kod w następujący sposób:Więcej składni aplikacji podobnej do haskellowej w skalazmie

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

Bardzo mi się nie podobał ten kod. Chciałbym kod, który jest bliżej do stylu Haskell, coś takiego:

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

Czy jest to możliwe. I dlaczego scalaz nie wdrożył go w ten sposób?

+0

Po prostu z ciekawości: Czego nie lubisz? Uważam, że "wersja skalowalna" jest czystsza w moim (moim) oku ... – Jan

+1

W Haskell po prostu napisałeś 'max <$> a <*> b', co ja osobiście bardzo lubię w każdej wersji Scalaz. –

+0

@TravisBrown jak napisalibyście to dla więcej niż dwóch argumentów? "zabawa <$> a <*> b <*> c"? – Jan

Odpowiedz

7

Wnioskowanie typu Scala jest znacznie bardziej ograniczone niż w Haskell (przeciążenie identyfikatora, które jest związane z JVM jako jedną z przyczyn). Wnioski przepływają od lewej do prawej, a typ argumentów funkcji można wywnioskować z poprzedniego kontekstu (jeśli w miejscu definicji oczekiwana jest funkcja z argem typu A), ale nie z tego, w jaki sposób są używane w definicja. Składnia scalaz udostępnia typy argumentów. Odwracanie go przez większość czasu wymusza zapisywanie typów argumentów funkcji, np.

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

Jest jednak wiele razy, kiedy mam do czynienia z istniejącą wartością funkcji, której pełny typ jest już znany. W tym przypadku naprawdę chciałbym mieć składnię "f <$> a <*>. Ponieważ mamy już składnię aplikacyjną wstecznego aplikatora '(a | @ | b) {math.max (_, _)} dla anonimowego przypadku funkcji, nie rozumiem, dlaczego nie możemy mieć naturalnego Haskella składnia dla przypadku wartości funkcji. –

4

Ty może przetłumaczyć wersję Haskell bezpośrednio do Scala, jeśli jesteś gotów być trochę bardziej gadatliwy:

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) 

Albo, jako jedną wkładką:

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

Lub:

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

Porządek jest odwrócony, ponieważ są to wywołania metod, a nie operatorów nawiasów, ale w zasadzie to samo, co max <$> a <*> b: odwzorowujemy funkcję na pierwszy element, a następnie stosujemy wynik do drugiego.

Powiązane problemy