如何在模拟类似 Haskell 解决方案的 F# 中编写可变参数函数? [英] How to write a variadic function in F# emulating a similar Haskell solution?

查看:14
本文介绍了如何在模拟类似 Haskell 解决方案的 F# 中编写可变参数函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我如何(如果有的话)模拟可变参数函数(不是方法)以便我可以编写

How can I (if at all) emulate variadic functions (not methods) so that I could write

sum 1 2 3
sum 1 2 3 4 5
sum 1 2 3 4 5 6 7
// etc.

上面的代码只是一个示例 - 显然,如果我必须总结一个列表,那么

The code above is just meant as an example - obviously if I would have to sum up a list then

[ 1; 2 ; 3] |> List.sum 

是一个更好的方法.

不过,我正在寻找一个结构相似的解决方案,例如 这个 Haskell 解决方案

However I am looking for a structurally similar solution like this Haskell solution

同样重要的是函数调用和参数值的正常语法保持不变.所以

What is also important is that the normal syntax for function calls and parameter values remains the same. So

sum 1 2 3

对比

sum(1, 2, 3)

这实际上意味着

let sum ([<ParamArray>] arr) = ...

在这种特定情况下不需要.

is not wanted in this specific case.

这一切的动机:我正在探索 F# 类型系统和语法的外围.而且我完全意识到我可能已经越过了可能的界限.

The motivation for all of this: I am exploring the outer fringes of F#'s type system and syntax. And I am fully aware of that I might have crossed the boundary of what is possible already.

PS:我的具体想法(我没有在这里描述)也可以完全不同地解决 - 所以我知道,所以我已经做了.因此,我的问题不是:如何以不同的方式解决这个问题,而是如何像 Haskell 一样在结构上解决这个问题.

PS: my concrete ideas (which I have not described here) can also be solved completely differently - so I know and so I have done already. Therefore my question is not: how can this be solved differently but how can this be solved structurally like Haskell.

PPS:如果您可以使整个解决方案递归,则加倍 Karma-Points.

PPS: Double Karma-Points if you can make the whole solution recursive.

推荐答案

你说的是函数,不是方法.所以 ParamArray 不是一个选项.

You said function, not method. So ParamArray is not an option.

您链接的 Haskell 代码基于推断的结果类型.

The Haskell code you linked is based on the inferred result type.

这里有一种根据 F# 中推断的结果类型进行解析的方法:

Here's a way to resolve based on the inferred result type in F#:

type T = T with
    static member inline ($) (T, r:'t->'t        ) = fun a b     -> a + b
    static member inline ($) (T, r:'t->'t->'t    ) = fun a b c   -> a + b + c
    static member inline ($) (T, r:'t->'t->'t->'t) = fun a b c d -> a + b + c + d

let inline sum (x:'a) :'r = (T $ Unchecked.defaultof<'r>) x

let x:int = sum 2 3 
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M

let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4  ) 10
let res3 = mult3Numbers 3 (sum 3 4 5) 10

更新

从 F# 4.1 开始,上面的代码不再起作用(请参阅注释),但这里有一个更好的示例,其中包含采用 n(无限)参数的递归多变量函数:

The above code doesn't work anymore as from F# 4.1 (see the comments) but here's a better example with a recursive polyvariadic function taking n (unlimited) arguments:

type T = T with
    static member        ($) (T, _:int    ) = (+)
    static member        ($) (T, _:decimal) = (+)

let inline sum (i:'a) (x:'a) :'r = (T $ Unchecked.defaultof<'r>) i x

type T with
    static member inline ($) (T, _:'t-> 'rest) = fun (a:'t) -> (+) a >> sum


let x:int = sum 2 3 
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M

let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4) (sum 2 2 3 3)
let res3 = mult3Numbers 3 (sum 3 4 5 11 13 20) 10

你也可以看看这个多元折叠.

这篇关于如何在模拟类似 Haskell 解决方案的 F# 中编写可变参数函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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