f#System.Char.ToUpper

f# 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)))

但这不起作用。我收到一个错误 'The expression was supposed to have unit but here has char.' 我做错了什么?是逻辑错误还是语法错误?

这需要一些拆包。

首先,你的核心错误:System.Char.ToUpper是一个函数。它需要一个字符和 returns 另一个字符。它不会以某种方式“更新”它的参数为新值。

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

在上面的代码中,我将函数的结果命名为 yy的值是'A',但是x的值还是'a'。调用函数后,x没有改变。

从这个错误开始,剩下的都是错误的。

SecondList.iter 是一个函数,它对于列表的每个元素,生成一些东西 "happen"。它不会用新内容替换 列表的每个元素,也不会创建新列表。它只是让每个元素发生一些事情。这种“something”的最简单示例是打印到控制台:

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

请注意,此函数有两个参数:表示需要发生的某事 的函数,以及从中获取元素的列表。在你的问题中,你似乎错过了第二个论点。 List.iter 怎么知道要使用哪个列表?

List.iter 的第一个参数需要是 returns unit 的函数。这是 F# 中的一种特殊类型,基本上表示 "no value"。当一个函数 return 没有值时,这意味着调用它的唯一原因是使 外部的事情 发生(在函数式编程中称为“side-effect").这就是为什么 List.iter 需要 return unit 的功能 - 这是额外的保护,防止意外提供错误的功能,就像你所做的那样,实际上:你提供的功能 returns char。这就是您收到错误消息的原因。

Third,就像 ToUpper 一样,调用 List.ofArray 不会以某种方式 "update" x 成为列表.相反,它是 returns 一个列表。如果您不给 returned 列表命名,它就会丢失。这意味着您调用 List.ofArray 的方式是徒劳的。

您实际需要的 是 (1) 获取字符串中的字符序列,然后 (2) 将其转换为每个字符均为大写的新序列,然后 (3) 将这些字符粘在一起以获得新字符串。

步骤 (1) 是 no-op,因为 .NET 字符串已经是字符序列(即它们实现了 IEnumerable<char>)。步骤 (2) 通过称为 Seq.map 的常见操作完成。这是一种通过将给定函数应用于每个元素来将序列转换为新序列的操作。本例中的 "given function" 将是 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