2016-02-22 3 views
1

Major редактировать, чтобы лучше отразить мое намерение:Предотвращение нежелательных комбинаций с использованием зависимых от пути типов?

// this *must* be outside of Team 
class Player 

class Team(val p1: Player, val p2: Player) { 
    type P = ??? // <-- what to put here ? see below ... 

    // perhaps I can somehow construct a union type: 
    // type P = p1.type union p2.type 
    // or perhaps the following : 
    // type P = Either[p1.type,p2.type] 
    // The purpose of `P` here is to define a type which can only hold p1 or p2 for values. 

    def position(p: P) = p match { 
    case `p1` => 1 
    case `p2` => 2 
    // Gotcha ! we never get here (=exactly what I want to enforce) if I can get the `P` right ! 
    } 
} 

val p1=new Player 
val p2=new Player 
val someP = new Player 
val t= new Team(p1,p2) 
t.position(t.p1) // allowed 
t.position(t.p2) // allowed 
t.position(p1) // allowed, since p1 is the same thing as t.p1, or is it ?! 
t.position(p2) // allowed, since p2 is the same thing as t.p2, or is it ?! 
t.position(someP) // I want this to *not* type-check : Required t.P, Found Player 

Оригинальный фрагмент здесь:

// this *must* be outside of Team 
class Player 

class Team(p1: Player, p2: Player) { 
    def position(p: Player) = p match { 
    case `p1` => 1 
    case `p2` => 2 
    // Ah-oh !! is it possible to prevent this using (probably path-dependent) types ? 
    } 
} 

val p1=new Player 
val p2=new Player 
val someP = new Player 
val t= new Team(p1,p2) 
t.position(p1) // allowed 
t.position(p2) // allowed 
t.position(someP) // I want this to *not* type-check with an error like "Required: t.Player, Found: Player" 
+0

Что делать вы имеете в виду типы, зависящие от пути? 't.position (someP)' всегда будет проходить проверку типа cos 'someP' от ожидаемого типа Player. Вы можете генерировать исключение в 'position', например' case _ => throw InvalidPlayerException' –

+0

. T.position (someP) всегда будет передавать проверку типа cos someP от ожидаемого типа. Игрок «Я знаю, и это точно проблема. Хотя я вижу путаницу ... Я отредактирую вопрос, чтобы лучше отразить мои намерения. –

ответ

1

Это может быть немного излишним, но это решает проблему

class Team(p1: Player, p2: Player) { 
    case class Membership(player: Player) 

    def position(m: Membership) = m.player match { 
    case `p1` => 1 
    case `p2` => 2 
    // Ah-oh !! is it possible to prevent this using (probably path-dependent) types ? 
    } 
} 

class Player 

val p1 = new Player 
val p2 = new Player 
val someP = new Player 

val t = new Team(p1, p2) 
val someT = new Team(someP, someP) 

val m1 = t.Membership(p1) 
val m2 = t.Membership(p2) 
val someM = someT.Membership(someP) 

t.position(m1) // allowed 
t.position(m2) // allowed 
t.position(someM) // This doesn't compile 
//type mismatch; found : Test.someT.Membership required: Test.t.Membership 
+0

Это на самом деле очень хорошее мышление: в основном вы говорите, чтобы передать «Player» в какой-то метод '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ' что аргумент действительно является членом, следовательно, необходимость «членства». Но характер такого доказывания (= экземпляр «членства» с желаемым игроком и командой в нем) таков, что если это предусмотрено, нет необходимости предоставлять плеер в качестве отдельного аргумента, поэтому достаточно экземпляра «Членство» , Правильно ? –

+0

Тогда я должен найти способ ограничить создание значений для 'Membership' теми, которые на самом деле правильны (т. Е. Нельзя создать членство для любой произвольной команды и игрока) ... имеет смысл ... если бы я мог только сделать он ближе к системе типов ... –

+0

Да, достаточно одного членства, я отредактировал матч, чтобы отразить поведение, которое вы хотите. –

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