简体   繁体   中英

Why can't I print this array in F#?

I have this list in C#:

List<string> words = new List<string> { "how", "are", "you" };

I can easily print the content of the list with:

foreach(string word in words)
   Debug.WriteLine(word);

Now I want to do the same in F# (I understand from over here that a List<T> is similar to a ResizeArray):

let words = ResizeArray<string>()
words.Add("how")
words.Add("are")
words.Add("you")

for word in words do
    Debug.WriteLine(sprintf "%s" word) 

Now the problem is, that in the for-loop word becomes null. What am I doing wrong here?

EDIT: Here is the full code. I have changed it to printf as suggested. Unfortunately I still get null in word when inside the for-loop:

let myFunction =
    let words = ResizeArray<string>()
    words.Add("how")
    words.Add("are")
    words.Add("you")

    for word in words do
        printf "%s" word // <-- word becomes null
    words

[<EntryPoint>]
let main argv = 
    ignore myFunction
    0 // return an integer exit code

I understand you want your code to look like C#. But F# is a functional language (not strictly, but that's main paradigm) and in these features lies the power of the language. First your collection. A more idiomatic type is a List. It's immutable which is one of the functional features of the language.

let words = ["how"; "are"; "you"]

Since it's immutable you expand it by creating a new collection. You can append an item at the beginning:

let moreWords = "Hello" :: words

or join one list with another one:

let evenMore = moreWords @ ["I"; "am"; "fine"]

Then iterating. For loop is purely imperative construct. Since we switched to a functional collection use one of the built-in List functions to iterate:

let prnt lst = lst |> List.iter (fun x -> printfn "%s" x)

This takes a list. Iterates it item by item. And executes the (fun x -> printfn "%s" x) function on each item.

Or you can play a bit and write your own function to go through all the elements and execute a function on each of them. One approach would be to use recursion and list matching:

let rec loopFn lst fn =
    match lst with
    | [] -> fn
    | head::tail ->
        fn head
        loopFn tail fn

This funciton takes a list and another function as arguments. Matches the list. If it's empty ( | [] ) - performs the function. Otherwise splits the list to head and the rest ( head::tail ) executes the function on the head ( fn head ) and loops further on the remaining items ( loopFn tail fn ).

To print the items pass to the function the list of words and a print function:

loopFn words (fun x -> printfn "%s" x)

or since printfn is a function itself you can simplify the call a bit:

loopFn words (printfn "%s")

This works:

for word in words do
    printf "%s" word

But if you really want debug output, are you loading the system.diagnostics namespace?

open System.Diagnostics

(Your code)

This worked for me without loading the namespace:

for word in words do
    System.Diagnostics.Debug.Write(sprintf "%s" word)

I suspect this is due to the lazy evaluating nature of F#. So, word is not actually assigned till it is used by the printf statement, and hence you cannot see the value in the debugger.

If you add another statement in your loop and set a breakpoint there, you will see the value of assigned value of word . See the snippet below -

let myFunction =
let words = ResizeArray<string>()
words.Add("how")
words.Add("are")
words.Add("you")

for word in words do
    printf "%s" word // 
    printf "%s" word // <-- SET A BREAKPOINT HERE AND VERIFY THE VALUE OF 'word'

words

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM