2017-02-18 39 views
3

我有一個請求,其轉換字符串的所有字符使用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))) 

但是這不起作用。我收到一個錯誤'表達本應該有單位,但這裏有字符。'我究竟做錯了什麼?這是邏輯還是語法上的缺陷?

回答

5

這需要一些拆箱。

首先,你的核心錯誤:System.Char.ToUpper是一個函數。它需要一個字符並返回另一個字符。它不會以某種方式「更新」它的論點到一個新的價值。

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

在上面的代碼中,我給該函數的結果命名爲yy的值爲'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#中的一種特殊類型,基本上意味着「沒有價值」。當一個函數沒有返回任何值時,這意味着調用它的唯一原因是使發生某種外部事件(在函數式編程中稱爲「副作用」)。這就是爲什麼List.iter要求功能返回unit - 它可以提供額外的保護,防止意外地提供錯誤的功能,就像您一樣,實際上:您提供的功能返回char。這就是您收到您收到的錯誤的原因。

,就像ToUpper,呼籲List.ofArray不會莫名其妙地「更新」 x是一個列表。相反,它返回的一個列表。如果你不給這個返回的名單一個名字,它將會丟失。這意味着你打電話List.ofArray的方式是徒勞的。

你真正需要什麼是:(1)取的字符序列中的字符串,然後(2)將其轉換爲一個新的序列,其中每個字符爲大寫,則(3)膠這些字符一起回來得到一個新的字符串。因爲.NET字符串已經是字符序列(即它們實現了IEnumerable<char>),所以步驟(1)是不可操作的。步驟(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 
+0

感謝您抽出時間來解釋這一切給我。我敢肯定,你可以說我是f#的新手。 – jynx678

+5

如果你是新手,這裏是一個很好的資源開始:https://fsharpforfunandprofit.com/ –