Function F#为函数指定(自定义)类型

Function F#为函数指定(自定义)类型,function,types,f#,type-constructor,Function,Types,F#,Type Constructor,尽管我在F#方面取得了很大的进步,但我仍然迷恋于各种构造函数和解构器语法 我正在运行递归模拟。其中一个参数是停止条件的函数。我有各种可能的停车条件可供选择。我让他们都有相同的签名。因此,我决定将这些函数锁定为自定义类型将是一件好事,也是一件有教育意义的事情——这样就不必发送任何与签名匹配的函数: type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -&

尽管我在F#方面取得了很大的进步,但我仍然迷恋于各种构造函数和解构器语法

我正在运行递归模拟。其中一个参数是停止条件的函数。我有各种可能的停车条件可供选择。我让他们都有相同的签名。因此,我决定将这些函数锁定为自定义类型将是一件好事,也是一件有教育意义的事情——这样就不必发送任何与签名匹配的函数:

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool) 
从教程中,我认为我做得对,对于一个区分大小写的联合,有一个类型名和一个相同的构造函数名(混淆…)。但现在我不知道如何将此类型应用于实际函数:

let Condition1 lastRet nextRet i fl =
    true
如何使条件1为StoppingCondition类型?我敢打赌这是微不足道的。但是我试着把StoppingCondition作为let之后的第一、第二或最后一个学期,不管有没有parens和colons。一切都是错误的

谢谢你的耐心

编辑:

我将尝试从四个答案中综合我所学到的东西(截至目前),都很好:

试图模仿这种模式:

s : string = "abc"
我试着写:

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool)

let condition1 lastRet nextRet i fl : StoppingCondition =  // BAD 
    //wrong for a type alias, totally wrong for a union constructor
    true
    //or
let condition1 : StoppingCondition lastRet nextRet i fl = // BAD again
    true
或其他插入的
:Stopping Condition
(尝试以构造函数的方式在该行中为其添加前缀)

现在我明白了,要想得到我想要的东西,我必须:

type StoppingCondition = | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool)
let conditionFunc1 lastRet nextRet i fl =   //...
    true
let stoppingCondition1 = StoppingCondition conditionFunc1 
    //or
let stoppingCondition2 = StoppingCondition <| (func lastRet nextRet i fl -> false) 
    //and there's another variation or 2 below
在我的例子中,没有足够的价值来处理包装器。但是类型别名可以工作:

type StoppingAlias = ReturnType -> ReturnType -> int -> float -> bool
let stoppingCondition:StoppingAlias = fun prevRet nextRet i x -> true
let b = stoppingCondition ret1 ret2 10 1.0  // b = true
我可能没有把我刚才所说的一切都说清楚,但我想我更接近了

编辑2:

旁注。我的问题是关于定义函数的类型。它使用类型别名和联合类型进行比较。在尝试执行这些操作的过程中,我还学习了使用类型别名:

这本书(来自:):

但这些都是错误的:

let (f2 : Adder) x y = x + y    // bad 
let (f3 x y) : (decimal -> decimal -> decimal) = x + y   // bad 
let (f3 : (decimal -> decimal -> decimal)) x y  = x + y  // bad
关于整个问题的一些讨论:

(而且,是的,“分配类型”也不是正确的说法。)

您不会“使其成为类型”
停止条件。您可以声明类型为
StoppingCondition
的值,并将
Condition1
作为DU case构造函数的参数传递:

let stop = StoppingCondition Condition1
然而,这意味着,每当您想要访问包含在单个DU案例中的函数时,您必须以某种方式对其进行模式匹配;这可能会变得烦人

您说您不希望任何满足签名的函数作为停止条件有效;但是,它似乎足够具体,可以避免“意外”传入一个“不适当”的函数-这样,您可以做一些更简单的事情-将
StoppingCondition
定义为特定函数类型的类型别名:

type StoppingCondition = ReturnType -> ReturnType -> int -> float -> bool

现在,您可以在需要指定类型的任何地方使用
StoppingCondition
,并且您传递/返回的实际值可以是满足签名的任何函数
ReturnType->ReturnType->int->float->bool
指定函数的返回类型如下所示:

let Condition1 lastRet nextRet i fl :StoppingCondition=
    true
type MyInput =
    { LastReturn : ReturnType
      NextReturn : ReturnType
      MyInt      : int
      MyFloat    : float }

type StopCondition = StopCondition of (MyInput -> bool)

let impossibleCondition = StopCondition (fun _ -> false)

let moreComplicatedCondition = StopCondition <| fun inp ->
    inp.MyInt < int (round inp.MyFloat)
当然,这不会编译,因为true的类型不正确

我怀疑你想要的实际定义更接近

let Condition1  :StoppingCondition=
    true
但是,由于类型看起来像是包含函数参数

在此基础上展开,您可以定义如下函数:

let Condition1=fun a b c d -> StoppingCondition(fun a b c d -> whatever)
但这整件事很难看


实际上,我认为最好将所有函数放在一个数组中,这将强制类型匹配

因此,在我看来,您可能希望使用
StoppingCondition
s创建一些预定义类型的停止条件

以下是一些可能的停止条件的示例:

let stopWhenNextGreaterThanLast = StoppingCondition (fun last next _ _ -> next > last)

let stopWhenLastGreaterThanLast = StoppingCondition (fun last next _ _ -> last> next)
type StoppingCondition =
    | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool)
    | Or of StoppingCondition * StoppingCondition
(我已经强调了停止条件定义中未使用的参数)

希望您能看到类型为
StoppingCondition
的这两个值

然后,如果给定一些参数,您可能需要一个函数来确定是否满足停止条件:

let shouldStop stoppingCond last next i value = 
    match stoppingCond with
    |StoppingCondition f -> f last next i value
此函数接受停止条件和递归的各种状态,并根据是否现在停止返回
true
false

这就是在实践中使用此方法所需的全部内容


您可以通过这样做来扩展此方法,以涵盖多种潜在的停止条件:

let stopWhenNextGreaterThanLast = StoppingCondition (fun last next _ _ -> next > last)

let stopWhenLastGreaterThanLast = StoppingCondition (fun last next _ _ -> last> next)
type StoppingCondition =
    | StoppingCondition of (ReturnType -> ReturnType -> int -> float -> bool)
    | Or of StoppingCondition * StoppingCondition
并修改
应停止
功能

let rec shouldStop stoppingCond last next i value = 
    match stoppingCond with
    |StoppingCondition f -> f last next i value
    |Or (stp1, stp2) -> (shouldStop stp1 last next i value) || (shouldStop stp2 last next i value)
现在,如果我们有一个条件,当它满足时,我们停止,或者如果我们有多个条件,我们可以检查它们是否满足

然后,您可以
将基本条件中的新停止条件组合在一起:

let stopWhenIIsEven = StoppingCondition (fun _ _ i _ -> i % 2 = 0)

let stopWhenValueIsZero = StoppingCondition (fun _ _ _ value -> value = 0.0)

let stopWhenIEvenOrValueZero = Or (stopWhenIIsEven, stopWhenValueIsZero)

如前所述,您必须从适当的函数构造一个
StoppingCondition
的实例,例如:

let Condition1 = StoppingCondition (fun _ _ _ _ -> true)`
一种不用奇怪的缩进或附加括号的好方法是反向管道:

let Condition1 = StoppingCondition <| fun lastRet nextRet i fl ->
    // Add function code here

谢谢我想我越来越近了。我想我同意你的猜测。我希望
Condition1
——而不是它的返回值——是类型
StoppingCondition
。所以第二个街区就在那条路上。但是现在在该块中,
Condition1
不再有任何参数。所以我没有什么工作要做。(真正的函数当然不仅仅是返回
true
——我只是省略了代码。)那么我如何在那里也得到参数呢?他们需要名字让我用。如果这听起来真的让人困惑或困惑——毫无疑问,这是因为我感到困惑,让人困惑。谢谢。@Romniee-我觉得你的方法有点奇怪,但我给出了一个解决方案。好的,谢谢。这很奇怪,因为我理解力差。谢谢,谢谢。我确实先做了一个类型别名。它成功了。我只是试着将单一案例合并作为练习。(我的在线示例教程使用简单类型,而不是用于单案例联合的函数…)我需要完成您对联合用法的解释。但我想我会以t的别名结束
let testStopCondition (StopCondition c) input = c input