2017-01-11 3 views
1

Я пытаюсь перенести общую библиотеку для Haskell в Scala. Тем не менее, я в настоящее время не очень доволен тем, как я решил функцию Generic Crush в Scala.Scala Несколько параметров типа, которые определены позже

Я определил следующие способы обработки функций Crush.

trait FRep[G[_],F[_]]{ 
    def frep[A](g1 : G[A]) : G[F[A]] 
    } 

trait Crush[B,A]{ 
    def selCrush : Assoc => A => B => B 
} 

Далее, я хотел определить функцию раздавливания, но здесь я столкнулся с проблемами. Проблема в том, что мне нужна эта особенность FRep, чтобы представить функцию Crush, но G (Generic) в frep позволяет только 1 параметр. Я решил это, используя типы лямбда, но у меня все еще есть некоторые проблемы для определения функции. Это подход, который я хотел бы работать:

def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]): B = { 
    def fCrush = new Crush[B,A]{ 
     override def selCrush= _ => f 
    } 
    return(rep frep(fCrush).selCrush(asc)(x)(z)) 
} 

Это, очевидно, дал ошибку, поскольку параметр в функции давке не то же самое, как типа А лямбда в неявной переменной повторении, которое должно быть таким же, чтобы использовать функцию Crush. Это ошибка, я получил:

<pastie>:677: error: type mismatch; 
found : x.type (with underlying type F[A]) 
required: A 
     return(rep frep(fCrush).selCrush(asc)(x)(z)) 

Таким образом, решение, которое я придумал, чтобы разбить функцию раздавливания в более части, так что я мог бы использовать один и те же А для функции раздавливания. Это текущее решение, которое составляет:

class CrushFunction[B,F[_]](asc : Assoc)(z : B)(implicit rep : FRep[({type AB[A] = Crush[B,A]})#AB,F]){ 
    def crush[A](f : A => B => B)(x : F[A]) : B = { 
     val crushVal = new Crush[B,A]{ 
      override def selCrush: Assoc => A => B => B = _ => f 
     } 
     return(rep.frep(crushVal).selCrush(asc)(x)(z)) 
    } 
} 

Итак, мой вопрос: Есть ли способ лучше решить эту проблему?

ответ

2

На самом деле единственное, что неправильно с вашим первым решением заключается в том, что вы оставили точку между rep и frep. Я также хотел бы посоветовать вам не использовать return в явном виде, а не затенять имена параметров типа (A):

def crush[B,A,F[_]](asc : Assoc)(f : A => B => B)(z : B)(x : F[A])(implicit rep : FRep[({type AB[X] = Crush[B,X]})#AB,F]): B = { 
    def fCrush = new Crush[B,A]{ 
     override def selCrush: Assoc => A => B => B = _ => f 
    } 
    rep.frep(fCrush).selCrush(asc)(x)(z) 
} 

Теперь вы можете спросить себя: почему это сообщение об ошибке, если все, что случилось это точка пропущена? Ну, scala поддерживает инфиксную нотацию. Он анализирует a b c d e как a.b(c).d(e). Но вы написали что-то вроде этого: a b(c).d(e). Это смущает парсер. Вы можете увидеть, что произойдет, когда вы добавите //print в свой код в REPL (версия 2.11.8 или выше, я думаю) и нажмите клавишу TAB.

Я отфильтровал всю трещину для вас. rep frep(fCrush).selCrush(asc)(x)(z) получает разобрано как:

rep.frep[A](fCrush.selCrush(asc)(x)(z)) 

В этом выражении x действительно необходимо иметь тип A вместо F[A].

Честно говоря, мне кажется, что это похоже на ошибку, которую скалак сумел разобрать ваш бесцельный код, полностью игнорируя скобки в этом процессе. Назовем это неудачным синтаксисом quirk :-)

+0

-Xlint для теневого типа param. Как бы вы разобрали «привет» + («мир»). Length'? Я думаю, они хотят добавить аннотацию, чтобы указать, какие участники (операторы) могут использоваться постоянно. Это поможет читаемости, но, возможно, правило Abide может предупредить об инсайде alnum, за которым не следует пробел (и т. Д.). –

+0

Вы правы. Это работает! Спасибо за отличное объяснение! – maffh

Смежные вопросы