如何将printf样式的函数传递给F#中的另一个函数 [英] How to pass a printf-style function to another function in F#

查看:102
本文介绍了如何将printf样式的函数传递给F#中的另一个函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在F#中创建一个函数,该函数接受printf样式的函数作为参数,并使用该参数输出数据.用法如下所示:

I'd like to make a function in F# that accepts a printf-style function as an argument, and uses that argument to output data. Usage would be something like the following:

OutputStuff printfn

我的第一个尝试是让编译器为我解决所有问题:

My first attempt was to let the compiler figure it all out for me:

let OutputStuff output =
    output "Header"
    output "Data: %d" 42

之所以失败,是因为它确定output是使用string并返回unit的函数,因此第二次调用失败.

That fails because it decides that output is a function taking string and returning unit, so the second call fails.

接下来,我尝试声明output具有与printfn相同的签名:

Next I tried declaring output to have the same signature as printfn:

let OutputStuff (output : Printf.TextWriterFormat<'a> -> 'a) =
    output "Header"
    output "Data: %d" 42

这失败了,因为编译器确定output的实际类型是Printf.TextWriterFormat<string> -> unit,因此第二次调用再次失败.它还会生成警告FS0064,该警告表明对output的首次调用导致代码的通用性低于类型注释,这是问题的症结所在.

This fails because the compiler decides that the real type of output is Printf.TextWriterFormat<string> -> unit, so again the second call fails. It also generates warning FS0064 indicating that the first call to output causes the code to be less generic than the type annotations, which is the crux of the issue here.

最后,我尝试将输出函数声明为单独的类型缩写:

Last, I tried declaring the output function as a separate type abbreviation:

type OutputMe<'a> = Printf.TextWriterFormat<'a> -> 'a
let OutputStuff (output : OutputMe<'a>) =
    output "Header"
    output "Data: %d" 42

此操作失败,结果与上一次尝试相同.

This fails with the same results as the previous attempt.

我如何说服编译器不要专门化output的类型并将其保留为Printf.TextWriterFormat<'a> -> 'a?

How do I convince the compiler to not specialize the type of output and leave it as Printf.TextWriterFormat<'a> -> 'a?

推荐答案

问题是,当您说(output : Printf.TextWriterFormat<'a> -> 'a)时,表示"存在,其中某些'a的输出需要Printf.TextWriterFormat<'a>'a".相反,您要说的是全部 'a输出可以使用Printf.TextWriterFormat<'a>并返回'a.

The problem is that when you say (output : Printf.TextWriterFormat<'a> -> 'a), that means "there is some 'a for which output takes a Printf.TextWriterFormat<'a> to an 'a". Instead, what you want to say is "for all 'a output can take a Printf.TextWriterFormat<'a> and return a 'a.

用F#表示很难理解,但是要用具有泛型方法的类型来实现:

This is a bit ugly to express in F#, but the way to do it is with a type with a generic method:

type IPrinter =
    abstract Print : Printf.TextWriterFormat<'a> -> 'a

let OutputStuff (output : IPrinter) =
    output.Print "Header"
    output.Print "Data: %d" 42

OutputStuff { new IPrinter with member this.Print(s) = printfn s }

这篇关于如何将printf样式的函数传递给F#中的另一个函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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