F# 中 printfn 的类型,静态与动态字符串 [英] Type of printfn in F#, static vs dynamic string

查看:24
本文介绍了F# 中 printfn 的类型,静态与动态字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始在 Mono 中玩弄 F#,出现了以下我不太明白的问题.查了printfnTextWriterFormat的资料也没有什么启发,所以想在这里问一下.

I just began toying around with F# in Mono and the following problem arose that I cannot quite understand. Looking up information on printfn and TextWriterFormat didn't bring enlightenment either, so I thought I'm going to ask here.

在 FSI 中,我运行以下内容:

In FSI I run the following:

> "hello";;
val it : string = "hello"
> printfn "hello";;
hello
val it : unit = ()

只是一个普通的字符串并打印出来.美好的.现在我想声明一个变量来包含相同的字符串并打印它:

Just a normal string and printing it. Fine. Now I wanted to declare a variable to contain that same string and print it as well:

> let v = "hello" in printfn v ;;
let v = "hello" in printfn v ;;
---------------------------^
...stdin(22,28): error FS0001: The type 'string' is not compatible with the type 'Printf.TextWriterFormat<'a>'

我从阅读中了解到 printfn 需要一个常量字符串.我也明白我可以用像 printfn "%s" v 这样的东西来解决这个问题.

I understood from my reading that printfn requires a constant string. I also understand that I can get around this problem with something like printfn "%s" v.

但是,我想了解这里打字的情况.很明显,"hello"string 类型,v 也是.那为什么会出现类型问题呢?printfn 有什么特别的吗?据我了解,编译器已经对第一个字符串的参数执行了类型检查,因此 printfn "%s" 1 失败.. 这当然不能用于动态字符串,但我假设对于静态情况,这只是编译器端的一种方便.

However, I'd like to understand what's going on with the typing here. Clearly, "hello" is of type string as well as v is. Why is there a type problem then? Is printfn something special? As I understand it the compiler already performs type-checking on the arguments of the first string, such that printfn "%s" 1 fails.. this could of course not work with dynamic strings, but I assumed that to be a mere convenience from the compiler-side for the static case.

推荐答案

好问题.如果看一下printfn的类型,就是Printf.TextWriterFormat<'a>->'a,您将看到编译器在编译时自动将字符串强制转换为 TextWriterFormat 对象,从而推断出适当的类型参数 'a.如果您想将 printfn 与动态字符串一起使用,您可以自己执行该转换:

Good question. If you look at the type of printfn, which is Printf.TextWriterFormat<'a> -> 'a, you'll see that the compiler automatically coerces strings into TextWriterFormat objects at compile time, inferring the appropriate type parameter 'a. If you want to use printfn with a dynamic string, you can just perform that conversion yourself:

let s = Printf.TextWriterFormat<unit>("hello")
printfn s

let s' = Printf.TextWriterFormat<int -> unit>("Here's an integer: %i")
printfn s' 10

let s'' = Printf.TextWriterFormat<float -> bool -> unit>("Float: %f; Bool: %b")
printfn s'' 1.0 true

如果字符串是静态已知的(如上例所示),那么您仍然可以让编译器推断 TextWriterFormat 的正确通用参数,而不是调用构造函数:

If the string is statically known (as in the above examples), then you can still have the compiler infer the right generic argument to TextWriterFormat rather than calling the constructor:

let (s:Printf.TextWriterFormat<_>) = "hello"
let (s':Printf.TextWriterFormat<_>) = "Here's an integer: %i"
let (s'':Printf.TextWriterFormat<_>) = "Float: %f; Bool: %b"

如果字符串确实是动态的(例如,它是从文件中读取的),那么您需要像我在前面的示例中所做的那样显式使用类型参数并调用构造函数.

If the string is truly dynamic (e.g. it's read from a file), then you'll need to explicitly use the type parameters and call the constructor as I did in the previous examples.

这篇关于F# 中 printfn 的类型,静态与动态字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆