F# 如何编写函数列表?
如果我有一个名为Person的类型和函数列表,例如F# 如何编写函数列表?,f#,F#,如果我有一个名为Person的类型和函数列表,例如 let checks = [checkAge; checkWeight; checkHeight] …其中每个函数都是(Person->bool)类型,我要做的是等效于 checkAge >> checkWeight >> checkHeight …但我事先不知道列表中有哪些函数,我该如何做 我尝试了以下方法 checks |> List.reduce (>>) …但这会产生以下错误 错误FS00
let checks = [checkAge; checkWeight; checkHeight]
…其中每个函数都是(Person->bool)类型,我要做的是等效于
checkAge >> checkWeight >> checkHeight
…但我事先不知道列表中有哪些函数,我该如何做
我尝试了以下方法
checks |> List.reduce (>>)
…但这会产生以下错误
错误FS0001:类型不匹配。期待
(人物->布尔)->(人物->布尔)->人物->布尔
但是给一个
(人物->布尔)->(布尔->'a)->人物->'a
类型“Person”与类型“bool”不匹配
我做错了什么?如果您有执行某些转换的函数,则
>
运算符很有用。例如,如果您有一个函数列表Person->Person
,可以将一个人变成另一个人
在您的例子中,似乎有函数Person->bool
,您希望构建一个组合函数,如果所有函数都返回true
,该函数将返回true
使用List.reduce
可以编写:
checks|> List.reduce (fun f g -> (fun p -> f p && g p))
也许更简单的选择是编写一个函数,该函数接受一个人并使用列表
let checkAll checks person = checks |> List.forall (fun f -> f person)
你可能不知何故偶然发现了一个可怕的概念。显然是伏地魔(别说他的名字!)的函数式编程
无需进一步ado,就可以直接进入代码:
type Person =
{ Name : string
Age : int
Weight : int
Height : int }
type Result =
| Ok of Person
| Fail
let bind f m =
match m with
| Ok p -> f p
| _ -> Fail
let (>=>) f1 f2 = f1 >> (bind f2)
let checkAge p =
if p.Age > 18 then Ok(p)
else Fail
let checkWeight p =
if p.Weight < 80 then Ok(p)
else Fail
let checkHeight p =
if p.Height > 150 then Ok(p)
else Fail
let checks = [ checkAge; checkWeight; checkHeight ]
let allcheckfunc = checks |> List.reduce (>=>)
let combinedChecks =
checkAge
>=> checkWeight
>=> checkHeight
let p1 =
{ Name = "p1"
Age = 10
Weight = 20
Height = 110 }
let p2 =
{ Name = "p2"
Age = 19
Weight = 65
Height = 180 }
allcheckfunc p1
combinedChecks p1
allcheckfunc p2
combineChecks p2
type Person=
{Name:string
年龄:整数
重量:整数
高度:int}
类型结果=
|人的Ok
|失败
设bind f m=
匹配
|Ok p->f p
|->失败
让(>=>)f1 f2=f1>>(绑定f2)
让检查p=
如果p.年龄>18,则Ok(p)
否则失败
设校核重量p=
如果p.重量<80,则正常(p)
否则失败
设检查高度p=
如果p.高度>150,则正常(p)
否则失败
让检查=[检查年龄;检查体重;检查身高]
让allcheckfunc=checks |>List.reduce(>=>)
让我们来核对一下=
支票
>=>检查重量
>=>检查高度
设p1=
{Name=“p1”
年龄=10
重量=20
高度=110}
设p2=
{Name=“p2”
年龄=19
重量=65
高度=180}
allcheckfunc p1
组合支票p1
allcheckfunc p2
combineChecks p2
在这一点上,我可以抛出很多奇怪的行话(不是真的,我不能…),但让我们看看我做了什么
- 我放弃了你的返回值bool,选择了另一种类型(Result),使用(标记该关键字!)Ok或Fail
- 然后让一个助手(绑定)从该结果类型中包装和展开内容
- 和一个新的操作符(=>)来组合reduce中的内容
请注意,第一个检查函数Fail将缩短整个链,并且或多或少会立即(不调用其他函数)返回Fail。此外,您将不知道它在该链中的何处发生了故障,或者在任何故障之前的哪些功能实际上发生了正常
也有一些方法可以在进行过程中累积错误,这样您就可以得到一个类型为“检查返回失败的反馈,但其他的都是错误”
代码大部分是从这里偷来的:
你可能想阅读整个网站的Wlaschin,甚至更多,以进入更精细和更难的细节,如果需要的话
祝您在通往酒店高层的旅途中好运。;-)
脚注:这通常称为a。它还没有完全完成,上面的代码中没有,但没关系……我认为它在您的情况下会起作用……看起来很适合这里。
如果你选择走这条路,你基本上有两个选择。
你可以全速前进,也可以走捷径
快速路线
您可以重写验证函数,以采用Person选项
,而不仅仅是普通的Person
let validAge (record:Record option) =
match record with
| Some rec when rec.Age < 65 && rec.Age > 18 -> record
| None -> None
全方位
或者,如果您懒惰并且不想在每个验证函数中匹配..,则可以编写更多代码。
(样本取自[])
首先要做一些设置。
我们将定义一个特殊的返回类型,以便获得有意义的错误消息
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
您还必须重写验证函数
let validAge (record:Record) =
if record.Age < 65 && record.Age > 18 then Success input
else Failure "Not the right age bracket"
无论哪种方式,请查看原始文章。
您还可以使用更多内容:)
编辑:我只是注意到我再次写这个答案太慢了。
此外,我认为Helge对concetp的解释也比我好。要使用>
操作符,右边的函数必须以左边的结果类型作为参数。checkAge
返回bool
,但是checkWeight
期望Person
。您希望最终结果是什么nify?@TeaDrivenDev我正在尝试组合函数,这样我就可以一次性调用结果,而不是一次一个地遍历每个函数。这一切都是从我试图在这个F#Snippets页面改进代码开始的……谢谢你的回答。我实际上是在编写一个包含函数列表的函数来概括代码段ons,组合它们并运行组合结果。该代码段手动组合函数,因此它特定于所讨论的问题。我可以这样做吗?也许……但我也这样做了。;-@Brunner我刚刚回来更新我的问题,并添加我的答案,这与您和Helge的答案基本相同。是的,在查看该代码段时,它看起来是d对我来说就像ROP一样,我试图应用这个原则。我最终得到的代码与你的代码略有不同(我没有使用DU),但我认为原则是一样的。现在我必须决定h=谁的答案被接受!他们都非常感谢
let bind switchFunction =
function
| Success s -> switchFunction s
| Failure f -> Failure f
let validAge (record:Record) =
if record.Age < 65 && record.Age > 18 then Success input
else Failure "Not the right age bracket"
checks |> List.reduce (fun acc elem -> acc >> bind elem)