переключить функцию и объект с помощью scalaz' |›

Я могу использовать оператор scalaz |>, когда хочу переключить функцию и объект, чтобы получить немного больше читабельности. Позвольте представить вам модельную функцию :

def length2(x:String) = x.length * 2
Теперь я могу написать ее двумя способами:
"aoeu" |> length2
length2("aoeu")
Но если я определю эту функцию более общей, она перестанет работать.
def length2(x:SeqLike[_,_]) = x.length * 2 length2("aoeu")  // ок "aoeu" |> length2 // не работает
Почему компилятор этого не понимает? Определенно существует неявное преобразование от String к некоторому смешению классов в признаке SeqLike.


person coubeatczech    schedule 15.01.2011    source источник
comment
Сложный. Сначала я думал, что это потому, что вы можете иметь только одно имплицитное за раз, но теперь кажется, что это может быть также скрытая где-то проблема дисперсии…   -  person Debilski    schedule 15.01.2011
comment
@Debilski, я не уверен, где |> определен в scalaz, но когда я попытался определить свой собственный, я думаю, что единственное неявное правило — это то, что мешало его применению: aoeu нужно было бы неявно преобразовать в класс с помощью |> метод, а затем снова SeqLike.   -  person huynhjl    schedule 16.01.2011
comment
Показать сообщение об ошибке. Не у всех есть доступный Scalaz, но сообщения об ошибках обычно объясняют, что происходит не так.   -  person Daniel C. Sobral    schedule 16.01.2011


Ответы (2)


scala> "aoeu" |> length2
<console>:14: error: type mismatch;
 found   : (scala.collection.SeqLike[_, _]) => Int
 required: (java.lang.String) => ?
       "aoeu" |> length2

Сообщение об ошибке довольно ясно.

Хотя существует неявное преобразование из String в SeqLike[_,_], преобразования из (SeqLike[_, _]) => Int в String => ? нет.

Это можно исправить с помощью следующего неявного преобразования:

implicit def liftFun[X, T <% X, U](f: (X) => U): (T) => U = {
  def g(t:T) = f(t)
  g _
}

Редактировать 2: это оператор без скалаза.

class Pipe[T](t:T) {
  def |%>[X, U](f: (X) => U)(implicit ev: T <%< X) = f(t)
}
implicit def toPipe[T](t:T) = new Pipe(t:T)

Затем вы можете использовать его следующим образом:

def l1(a:String) = a.length
def l2(a:Seq[_]) = a.length * 2

"abc" |%> l1
"abc" |%> l2

Это позволяет |%> использовать функцию, которая работает не напрямую с T, а с X, если есть признаки неявного преобразования из T в X.

person huynhjl    schedule 15.01.2011

Не используйте экзистенциальные типы без необходимости. Они ломают вещи, и здесь не требуются.

С другой стороны, увидев ошибку в другом ответе, все стало более ясно. При использовании |> запрашиваются два неявных преобразования. Будет ли это работать, если вы объявите это так:

def length2[CC <% SeqLike[_, _]](x: CC) = x.length * 2
person Daniel C. Sobral    schedule 15.01.2011
comment
Это возвращает: could not find implicit value for evidence parameter of type (CC) => scala.collection.SeqLike[_, _] - person huynhjl; 16.01.2011