Можно ли использовать оператор конвейера в F # для передачи аргумента в конструктор? - PullRequest
7 голосов
/ 06 ноября 2010

Этот код переворачивает строку:

let reverse (s : string) = new string(s.ToCharArray() |> Array.rev)

Можно ли это переписать, используя оператор конвейера, чтобы передать требуемый аргумент в конструктор string()?Например, это выглядит более идиоматично:

// Doesn't compile:
let reverse (s : string) = s.ToCharArray() |> Array.rev |> new string

Точно так же, почему я не могу использовать оператор string следующим образом?

let reverse2 (s : string) = s.ToCharArray() |> Array.rev |> string

Вот оно в действии:

> reverse2 "foo" ;;
val it : string = "System.Char[]"

Возвращает тип, а не "oof".

Ответы [ 2 ]

9 голосов
/ 06 ноября 2010

Как уже упоминал Стивен, лучше всего определить новую функцию, которая вызывает конструктор. Вы можете поместить его в модуль с именем String (в некотором вашем пространстве имен), чтобы вы почувствовали то же чувство, что и при работе с другими функциями F #. Я бы, наверное, использовал:

module String =
  let create (c:char[]) = new string(c)

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

let inline ctor< ^R, ^T when ^R : 
        (static member ``.ctor`` : ^T -> ^R)> (arg:^T) =
    (^R : (static member ``.ctor`` : ^T -> ^R) arg)

И используйте такую ​​функцию:

"ABC".ToCharArray() |> Array.rev |> ctor<string, _>;;

Функция ctor по существу требует, чтобы тип, указанный в качестве параметра первого типа, имел конструктор и вызывал конструктор (другой параметр типа является аргументом конструктора и выводится компилятором). Но это на самом деле просто любопытство - определение собственной функции - лучший подход.

9 голосов
/ 06 ноября 2010

Нет, оператор канала может использоваться только с функциями F #, его нельзя использовать с конструкторами классов, методами-членами или статическими методами. Причина в том, что перегрузка, поддерживаемая этими методами, усложнит вывод типа F #. Однако, если вы действительно хотите использовать конвейерную связь, вы можете отобразить каждый элемент массива char в строку и затем передать эту последовательность в Seq.concat "":

s.ToCharArray() |> Array.rev |> Seq.map(string) |> String.concat ""

Или вы можете заключить вызов строкового конструктора в метод F #:

let stringCArrCtor (carr: char[]) =
    new string(carr)

s.ToCharArray() |> Array.rev |> stringCArrCtor

И чтобы ответить на ваш последний вопрос,

s.ToCharArray() |> Array.rev |> string

нельзя использовать, потому что это эквивалентно

(s.ToCharArray() |> Array.rev).ToString()

и метод Array ToString () не переопределяется, поэтому он просто возвращает отображаемое имя типа по умолчанию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...