2015-02-27 2 views
0

Просто для удовольствия я играл с эмуляцией типов в F #, используя представленные идеи here. Я создал класс следующего типа для представления значений, которые имеют «преемник», например. Следующий 1 = 2, рядом сегодня = завтра и т.д.:Сообщение об ошибке с ограничениями общего шифрования F #

type Next = Next with 
    static member (++) (Next, x:int) = x + 1 
    static member (++) (Next, x:DateTime) = x.AddDays 1.0 
let inline next x = Next ++ x 

let v1 = next 1 // v1 = 2 
let v2 = next DateTime.Now // v2 = Now + 1 day 

Теперь я хочу использовать "nextable" типы в обобщенном классе:

type UsesNextable<'T>(nextable: 'T) = // Compile error 1 
    member inline this.Next = 
     let v = next nextable   // Compile error 2 
     v.ToString() 

Но я получаю следующие ошибки:

  1. Подпись и реализация несовместимы, поскольку параметр типа в классе/сигнатуре имеет другое требование времени компиляции к элементу в члене/реализации
  2. Подпись и реализация несовместимы, потому что объявление параметра типа «T» требует ограничения формы (Next или^T): (static member (++): Next *^T -> ^? 155882)

Меня больше интересует то, что вторая ошибка пытается сказать. Что означает криптоват? 155882? Я предполагаю, что это может иметь какое-то отношение к тому, что вы не можете разрешить этот тип. Кроме того, при условии, что он пытается вывести ограничение быть:

(Next or ^T) : (static member (++) : Next * ^T -> ^T) 

ли даже можно указать «или» состояние с помощью when 'T:...? Я не могу понять действительный синтаксис.

Наконец,^T предлагает statically resolved type parameter, но в документации говорится, что они не могут использоваться для типов. Несмотря на это, я попытался изменить «T to^T», но все же получил те же ошибки.

Я понимаю, что этот пример злоупотребляет системой типов, поэтому я не предполагаю, что компилятор должен иметь возможность обрабатывать его. Однако, для моих собственных интересов, я хотел бы знать, что действительно означают сообщения об ошибках!

ответ

5

Проблема в том, что .NET не поддерживает статические ограничения. F # разрешает им встраивать функции, которые скомпилированы в статические методы, но не может кодировать его в стандартный тип .NET. В вашем коде типичный тип, который вы хотите создать, будет иметь параметр типа со статическим ограничением, которое .NET не может представлять.

Вы можете изменить свой метод к статическому электричеству, и он будет работать нормально:

type UsesNextable() = 
    static member inline Next(nextable) = 
     let v = next nextable 
     v.ToString() 

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

type UsesNextable<'T>() = 
    static member inline NextOf(n:'U) = let v = next n in v.ToString() 

но не в этом:

type UsesNextable<'T>() = 
    static member inline NextOf(n:'T) = let v = next n in v.ToString() 

Решив первую проблему, вы увидите, что оба сообщения об ошибках исчезают, потому что вторая связана с первой, где система типов не может кодировать ограничение, но теперь она может разобраться в этом. ^?155882 представляет собой переменную типа статического ограничения, которую система типов не могла вывести.

Обратите внимание, что переход от 'T к ˆT ничего не меняет, на самом деле, как относится к одной и той же переменной типа, единственное, что вы вынуждены использовать шляпу при вызове метода.

Наконец о том, что вы не можете написать:

let inline next v = ((Next or ^T) : (static member (++) : Next * ^T -> ^T) Next, v) 

, что это явно ошибка, потому что F # можно сделать вывод, но вы не можете писать что не соответствует. Я уже сообщал об этом некоторое время назад, и они сказали мне, что они исправят это в будущем.

Есть много способов, чтобы обойти это ограничение, заставляя F # вывести тип вместо того, чтобы писать его непосредственно, вот один лайнер решение:

let inline next v = ((^Next or ^T) : (static member (++) : ^Next * ^T -> ^T) Next, v) 

Это создаст предупреждение, но вы можете отключить его nowarn директивы или путем добавления параметра к функции, содержащей экземпляр типа Next.

+0

Это отличный ответ - спасибо! – Akash

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