Оператор Overload в F#: (/)

Я хотел бы перегрузиться (/) оператор в F# для строк и сохранить значение для чисел.

/// Combines to path strings
let (/) path1 path2 = Path.Combine(path1,path2)

let x = 3 / 4 // doesn't compile

Если я пробую следующий, я получаю "Предупреждение, что 29 Дополнительных участников не могут обеспечить перегрузки оператора. Рассмотрите определение оператора как часть определения типа вместо этого".

/// Combines to path strings
type System.String with
  static member (/) (path1,path2) = Path.Combine(path1,path2)

Какие-либо идеи?

С уважением, вилкообразный

13
задан Guy Coder 12 April 2016 в 12:34
поделиться

3 ответа

Вы не можете предоставить перегруженные операторы для существующих типов. Один из вариантов - использовать другое имя оператора (как предлагает Натахан). Однако вы также можете определить новый тип для представления путей в вашем коде F # и предоставить оператор / для этого типа:

open System    

// Simple type for representing paths
type Path(p) =
  // Returns the path as a string
  member x.Path = p 
  // Combines two paths
  static member ( / )(p1:Path, p2:Path) = 
    Path(IO.Path.Combine(p1.Path, p2.Path))

let n = 4 / 2
let p = Path("C:\\") / Path("Temp")

Это дает одно важное преимущество - делая типы более явными, вы даете type checker - дополнительная информация, которую он может использовать для проверки вашего кода. Если вы используете строки для представления путей, вы можете легко спутать путь с какой-либо другой строкой (например, с именем). Если вы определите свой тип Путь , проверка типов предотвратит эту ошибку.

Более того, компилятор не позволит вам (просто) неправильно комбинировать пути (что может легко произойти, если вы представляете пути в виде строк), потому что p + p не определен (вы можете использовать только / , который правильно использует Path.Combine ).

20
ответ дан 1 December 2019 в 17:55
поделиться

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

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

type DivisionOperations =
  static member Divide(x:int, y:int) = x / y
  static member Divide(path1, path2) = Path.Combine(path1, path2)

let inline div< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Divide : ^a * ^b -> ^c)> a b = ((^t or ^a) : (static member Divide : ^a * ^b -> ^c) (a, b))

let inline (/) x y = div<DivisionOperations, _, _, _> x y
9
ответ дан 1 December 2019 в 17:55
поделиться

Я не думаю, что это возможно в F#, основываясь на чтении документации по перегрузке.

Вместо этого я бы предложил вам создать свою собственную функцию, которая выглядит как /, но не является таковой. Что-то вроде:

let (</>) path1 path2 = Path.Combine (path1,path2)

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

* Я думаю, что единственная причина, по которой + для строк выглядит нормально, - это чрезмерное увлечение. После долгого использования Haskell или Caml первые несколько минут после перехода на другой язык "foo" + "bar" выглядят ужасно.

6
ответ дан 1 December 2019 в 17:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: