2015-07-01 5 views
2

Таким образом, в Скале мы имеем типичную подпись объектива, как:Как реализовать параметрические линзы, которые меняют тип состояния

case class Lens[O,V](get: O => V, set: (O,V) => O) 

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

case class Lens[O[_],A,B](get: O[A] => A, set: (O[A],B) => O[B]) 

С A и B имеют смысл для O[_] Мой вопрос есть. Неужели это перестает быть изоморфным? Есть ли более простой способ, не нарушая некоторые правила?

ответ

1

Я думаю, что для определения правильной абстракции было бы полезно иметь конкретный тип объектива.

Однако, для вашего конкретного примера, есть что-то мы можем сказать:

case class Lens[O[_],V[_],A,B](get: O[A] => V[A], set: (O[A],V[B]) => O[B]) 

Я не думаю, что этот вид объектива может состоять. Для составления линз результат get должен быть способен подавать в set. Но здесь результат get - V[_], тогда как set нуждается в O[_].

В качестве дополнительного объяснения, вот еще один возможный вид полиморфных линзы, но это, вероятно, не тот, который соответствует вашим потребностям:

trait Lens[T[_]] { 
    def get[A](t: T[A]): A 
    def set[A,B](t: T[A], x: B): T[B] 
} 

Он может состоять как так:

def composeLenses[T[_],U[_]](lens1: Lens[T], lens2: Lens[U]) = 
    new Lens[({type x[A] = T[U[A]]})#x] { 
    def get[A](t: T[U[A]]): A = lens2.get(lens1.get(t)) 
    def set[A,B](t: T[U[A]], x: B): T[U[B]] = lens1.set(t, lens2.set(lens1.get(t), x)) 
    } 

Я бы не смог точно определить определение Lens - для этого мне пришлось использовать этот конкретный корпус:

case class Box[A](x: A) 

def boxBoxGet[A](b: Box[Box[A]]): A = ??? 
def boxBoxSet[A,B](b: Box[Box[A]], x: B): Box[Box[B]] = ??? 
0

В haskell lens и в monocle полиморфные линзы имеют 4 типа параметров. Они эквивалентны следующая реализация:

case class PLens[S, T, A, B](get: S => A, set: B => S => T) 

Тогда monomoprhic линзы являются просто типом псевдоним:

type Lens[S, A] = PLens[S, S, A, A] 

Вы можете прочитать параметры по 4 типа, как: если я изменяю А до В внутри S затем я получаю T.

eg

S = (Int, String) 
T = (Long, String) 
A = Int 
B = Long