为什么我不能在f#中打印这个数组?

时间:2022-03-23 13:25:58

I have this list in C#:

我在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):

现在我想在f#中做同样的事情(我从这里了解到,List 与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?

现在问题是,在for循环中,这个词变成了null。我在这里做错了什么?

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:

编辑:这里是完整的代码。我已经把它改成了printf。不幸的是,在for循环中,我仍然会得到null。

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

3 个解决方案

#1


2  

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.

我怀疑这是由于f#的惰性评估特性所致。因此,在printf语句使用它之前,word并没有被分配,因此您无法在调试器中看到值。

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

#2


4  

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.

我理解您希望您的代码看起来像c#。但是f#是一种函数式语言(不是严格意义上的,但这是主要的范例),并且在这些特性中,语言的力量。首先你的收藏。一个更习惯的类型是列表。它是不可变的,这是语言的功能特征之一。

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:

然后迭代。For循环是完全必要的构造。由于我们切换到功能集合,使用一个内置的列表函数来迭代:

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.

这需要一个列表。逐项迭代它。并在每个项目上执行(fun x -> printfn“%s”)函数。

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).

这个函数接受一个列表和另一个函数作为参数。匹配的列表。如果它是空的(|[])——执行该函数。否则,将列表拆分为头部和其他(头部::tail)执行头部(fn头部)的功能,并在其余的项上进一步循环(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:

或者因为printfn是一个函数本身你可以简化它的调用:

loopFn words (printfn "%s")

#3


2  

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)

#1


2  

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.

我怀疑这是由于f#的惰性评估特性所致。因此,在printf语句使用它之前,word并没有被分配,因此您无法在调试器中看到值。

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

#2


4  

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.

我理解您希望您的代码看起来像c#。但是f#是一种函数式语言(不是严格意义上的,但这是主要的范例),并且在这些特性中,语言的力量。首先你的收藏。一个更习惯的类型是列表。它是不可变的,这是语言的功能特征之一。

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:

然后迭代。For循环是完全必要的构造。由于我们切换到功能集合,使用一个内置的列表函数来迭代:

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.

这需要一个列表。逐项迭代它。并在每个项目上执行(fun x -> printfn“%s”)函数。

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).

这个函数接受一个列表和另一个函数作为参数。匹配的列表。如果它是空的(|[])——执行该函数。否则,将列表拆分为头部和其他(头部::tail)执行头部(fn头部)的功能,并在其余的项上进一步循环(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:

或者因为printfn是一个函数本身你可以简化它的调用:

loopFn words (printfn "%s")

#3


2  

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)