2017-02-18 9 views
3

У меня есть упражнение, которое запрашивает функцию, которая преобразует все символы строки в верхний регистр, используяе # System.Char.ToUpper

System.Char.ToUpper 

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

let x = s.ToCharArray() 
List.ofArray x 

Далее, я думал, что я хотел бы использовать List.iter перебирать мой список и использовать функцию System.Char.ToUpper на каждый персонаже.

List.iter (fun z -> (System.Char.ToUpper(z))) 

Это не работает. Я получаю сообщение об ошибке «Выражение должно было иметь единицу, но здесь есть символ». Что я делаю не так? Это ошибка в логике или синтаксисе?

ответ

5

Для этого требуется распаковка.

Во-первых, Ваша основная ошибка: System.Char.ToUpper - это функция. Он принимает символ и возвращает другой символ. Это не так "update" его аргумент к новому значению.

let x = 'a' 
let y = System.Char.ToUpper x // y = 'A', x = 'a'. 

В приведенном выше коде, я даю имя y к результату функции. Значение y составляет 'A', но значение x по-прежнему 'a'. После вызова функции x не изменился.

С этой целью следует следующее.

Второй, List.iter - это функция, которая для каждого элемента списка заставляет что-то «случиться». Это не заменить каждый элемент списка с чем-то новым, и он не создает новый список. Он просто делает что-то происходит для каждого элемента. Простейшим примером такой «то» печатает к консоли:

List.iter (fun x -> printfn "%i" x) [1; 2; 3] // Prints "1", then "2", then "3" 

Обратите внимание, что эта функция принимает два аргумента: функцию, которая представляет что-то, что должно произойти, и список, из которого в взять элементы. В вашем вопросе вам, кажется, не хватает второго аргумента. Как мог бы List.iter узнать, какой список использовать?

Первый аргумент List.iter должен быть функцией, которая возвращает unit. Это особый тип в F #, который в основном означает «no value». Когда функция не возвращает значение, это означает, что единственная причина для его вызова заключалась в том, чтобы сделать что-то внешнее произошло (известно в функциональном программировании как «побочный эффект»). Вот почему List.iter требует, чтобы функция возвращала unit - это дополнительная защита от случайной подачи неправильной функции, как и вы, на самом деле: функция, которую вы предоставили, возвращает char. Вот почему вы получаете полученную вами ошибку.

Третий, так же, как с ToUpper, называя List.ofArray не каким-то образом «обновление» x быть списком.Вместо этого он возвращает список. Если вы не дадите этому возвращенному списку имя, оно просто будет потеряно. Это означает, что способ, которым вы звоните List.ofArray, бесполезен.

Что вам нужно - (1) принять последовательность символов в вашей строке, затем (2) преобразовать ее в новую последовательность, где каждый символ является верхним регистром, затем (3) склеить эти символы вместе для получения новой строки.

Шаг (1) - это не-op, потому что строки .NET - это уже последовательности символов (т. Е. Они реализуют IEnumerable<char>). Этап (2) выполняется посредством общей операции, называемой Seq.map. Это операция, которая преобразует последовательность в новую последовательность, применяя данную функцию к каждому элементу. «Данная функция» в этом случае будет System.Char.ToUpper. Шаг (3) может быть выполнен с помощью String.concat, но вам нужно сначала преобразовать каждый символ в строку, потому что String.concat берет последовательность строк, а не символов.

let chars = s 
let upperChars = Seq.map System.Char.ToUpper chars 
let strChars = Seq.map string upperChars 
let result = String.concat "" strChars 

Или это может быть сделано в течение более короткого пути, не давая результата каждого шага в отдельное имя, но по конвейеру каждый результат прямо в следующей операции:

let result = 
    s 
    |> Seq.map System.Char.ToUpper 
    |> Seq.map string 
    |> String.concat "" 

И наконец, там на самом деле гораздо более короткий способ сделать это, но это настолько смехотворно очевидно, что это похоже на обман.

Дело в том, что строки являются последовательностями, для них имеет смысл иметь все операции последовательности. И угадай что? Они делают! В частности, имеется функция String.map, которая делает то же самое, как Seq.map, но для строк:

let result = String.map System.Char.ToUpper s 
+0

Благодарим Вас за время, чтобы объяснить все, что мне. Я абсолютно не знаком с f #, поскольку, я уверен, вы могли бы сказать. – jynx678

+5

Если вы новичок, вот отличный ресурс для запуска: https://fsharpforfunandprofit.com/ –