[英]F# Function with variable types
I have a question on making a function generic so that I can reuse the behavior. 我有一个关于使函数通用的问题,以便我可以重用该行为。 I have a situation where I want to perform the same set of actions whether the data is a
float
or a string
. 我有一种情况,我想执行相同的操作集,无论数据是
float
还是string
。 I have included a bit of the data model so you can see what I am doing. 我已经包含了一些数据模型,所以你可以看到我在做什么。 Near the bottom I have two different functions in the
DataSeries
module, simpleHigh
and preferredHigh
. 靠近底部我有两个不同的功能
DataSeries
模块, simpleHigh
和preferredHigh
。 The simpleHigh
function does exactly what I want. simpleHigh
函数完全符合我的要求。 You can see that in both cases, float
or string
, I am using the same set of functions. 您可以看到在两种情况下,
float
或string
,我使用相同的函数集。
Ideally I could do what I attempt to do in the preferredHigh
function. 理想情况下,我可以在
preferredHigh
函数中执行我尝试执行的操作。 I define a single function and then use it for both conditions. 我定义了一个函数,然后将它用于两个条件。 The compiler complains though saying there is a type mismatch.
编译器抱怨虽然说类型不匹配。 I tried making the inner
high
function take a type argument: 我尝试使内部
high
函数采用类型参数:
let high<'T> v = (Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value))
But because it is contained inside another function definition the compiler says, "Explicit type parameters may only be used on module or member bindings". 但是因为它包含在另一个函数定义中,编译器说,“显式类型参数只能用于模块或成员绑定”。
Am I fighting a loosing battle here? 我在这里打一场失败的战斗吗? Should I just settle with the simple version?
我应该解决这个简单版本吗? My instinct tells me I am missing simple subtle and simple here.
我的直觉告诉我,我在这里错过了简单的微妙和简单。 I would rather reuse the behavior if possible instead of writing the exact some thing twice.
我宁愿重用这种行为,如果可能的话,而不是写两次确切的东西。 Should I take a different approach?
我应该采取不同的方法吗? All feedback welcome!
欢迎所有反馈!
open System
type Observation<'T> = {
ObsDateTime : DateTimeOffset
Value : 'T
}
type Result =
| Float of float
| String of string
type DataSeries =
| Float of Observation<float> seq
| String of Observation<string> seq
module DataSeries =
let summarise
(f: float Observation seq -> float)
(s: string Observation seq -> string)
(ds: DataSeries) =
match ds with
| DataSeries.Float v -> f v |> Result.Float
| DataSeries.String v -> s v |> Result.String
// What works
let simpleHigh ds =
summarise
(Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value))
(Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value))
ds
// What I would rather write
let preferredHigh ds =
let high v = (Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value))
summarise
high
high
ds
The way you have preferredHigh
written right now, it doesn't compile for an entirely different reason: high
is a function of two arguments (one explicitly defined v
and another coming from the function composition), but you're passing it to summarise
, which expects a function of one argument. 你
preferredHigh
的方式现在很高兴,它不会因为一个完全不同的原因而编译: high
是两个参数的函数(一个明确定义v
,另一个来自函数组合),但是你要传递它来summarise
,期望一个参数的功能。
So, the obvious way would be to remove the extra argument v
: 所以,显而易见的方法是删除额外的参数
v
:
let high = (Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value))
However, this wouldn't compile for the reason that you have already noted: the compiler determines the type of high
based on the first usage as float Observation seq -> float
, and then refuses to accept it in the second usage, because it doesn't match string Observation seq -> string
. 但是,由于您已经注意到,这不会编译:编译器根据第一次使用确定
high
类型为float Observation seq -> float
,然后在第二次使用时拒绝接受它,因为它没有匹配string Observation seq -> string
。
This (as you probably already know) is due to the fact that in F# values cannot be generic, unless you write them as such explicitly. 这(你可能已经知道)是由于F#值不能是通用的,除非你明确地写它们。 Aka "value restriction" .
阿卡“价值限制” 。
However, functions can be generic. 但是,功能可以是通用的。 Even nested functions can: even though you can't write the generic parameters explicitly, the compiler would still infer a generic type for a nested function where appropriate.
即使嵌套函数也可以:即使您无法显式地编写泛型参数,编译器仍会在适当的位置推断嵌套函数的泛型类型。
From this, the solution is obvious: make high
a function, not a value. 从这一点来看,解决方案显而易见:
high
功能,而不是价值。 Give it an argument, and don't forget to apply the composed function to that argument, so that the resulting function doesn't end up with two arguments (aka "eta-abstraction" ): 给它一个参数,并且不要忘记将组合函数应用于该参数,以便结果函数不会以两个参数结尾(也称为“eta-abstraction” ):
let high x = (Seq.sortBy (fun x -> x.Value) >> Seq.last >> (fun x -> x.Value)) x
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.