我有一个练习,要求使用
将字符串的所有字符转换为大写的函数System.Char.ToUpper
所以首先,我将字符串更改为char数组,然后将数组更改为字符列表
let x = s.ToCharArray()
List.ofArray x
接下来,我认为我将使用list.iter迭代我的列表并使用system.char.toupper功能。
List.iter (fun z -> (System.Char.ToUpper(z)))
这不起作用。我遇到了一个错误,"表达式应该有单位,但这里有char。"我究竟做错了什么?它是逻辑还是语法的缺陷?
这需要一些解压缩。
首先,您的核心错误:System.Char.ToUpper
是一个函数。它需要一个char并返回另一个炭。它不会以某种方式" 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#中的一种特殊类型,基本上意味着"无值"。当函数不返回值时,这意味着调用它的唯一原因是使外部发生(在功能编程中已知为" side-effect ")。这就是为什么List.iter
要求函数返回unit
的原因 - 实际上,它是不小心提供错误功能的额外保护,实际上:您提供的功能返回char
。这就是为什么您会收到收到的错误。
第三就像ToUpper
一样,将List.ofArray
调用并不是"更新" x
作为列表。相反,它返回列表。如果您不给返回的列表一个名称,它将丢失。这意味着您打电话给List.ofArray
是徒劳的。
您实际需要的是(1)键入字符串中的字符序列,然后(2)将其转换为每个字符的新序列,然后(3)胶那些角色回到一起以获取一个新的字符串。
步骤(1)是一个no-op,因为.NET字符串已经是字符的序列(即它们实现IEnumerable<char>
)。步骤(2)是通过称为Seq.map
的常见操作来完成的。这是通过将给定函数应用于每个元素将序列转换为新序列的操作。在这种情况下,"给定功能"将为System.Char.ToUpper
。步骤(3)可以通过String.concat
完成,但是您需要先将每个char转换为字符串,因为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