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