Я пытаюсь создать инфиксный оператор, чтобы System.Text.StringBuilder
было немного проще в использовании.
У меня есть следующая встроенная функция, использующая статически разрешенные параметры типа:
let inline append value builder = (^T : (member Append : _ -> ^T) (builder, value))
который обрабатывает все перегрузки StringBuilder.Append
. Это отлично работает как обычная функция:
StringBuilder()
|> append 1
|> append " hello "
|> append 2m
|> string
// Result is: '1 hello 2'
Когда я пытаюсь использовать определение инфиксного оператора, например:
let inline (<<) builder value = append value builder
, он работает, когда все параметры в цепочке одинаковые тип:
StringBuilder()
<< 1
<< 2
<< 3
|> string
// Result is: '123'
, но не работает с параметрами разных типов:
StringBuilder()
<< 1
<< "2" // <- Syntax error, expected type 'int' but got 'string'.
<< 123m // <- Syntax error, expected type 'int' but got 'decimal'.
Ожидаемый тип, по-видимому, определяется первым использованием оператора <<
в цепочке. Я бы предположил, что каждый <<
будет применяться отдельно.
Если цепочка разделена на отдельные шаги, компилятор снова счастлив:
let b0 = StringBuilder()
let b1 = b0 << 1
let b2 = b1 << "2"
let b3 = b2 << 123m
b3 |> string
// Result is: '12123'
Можно ли создать такой оператор ?
Edit
Хакерское «решение», похоже, состоит в том, чтобы передавать промежуточные результаты через функцию идентификации всякий раз, когда изменяется тип аргумента:
StringBuilder()
<< 1 // No piping needed here due to same type (int)
<< 2 |> id
<< "A" |> id
<< 123m
|> string
// Result is: '12A123'