我是F#的新手,并且一直在关注指南,试图让一段代码工作,但事实并非如此。
我通过继承创造单人和合作运动的类型。
然后我使用模式匹配来了解类型,如果是合作运动,也可以获得玩家数量。然后相应地排名。
然而,我一直在收到错误。我在这上面跟着微软的例子,我真的不明白错误。我没有函数式编程背景。
/**
* @return mixed
*/
public function lastAnswer() {
if( class_exists( Config::get( 'account.models.discussion' ) ) ) {
return $this->hasOne( Config::get( 'account.models.answer' ) )->latest();
}
return null;
}
答案 0 :(得分:6)
问题已经得到解答,但因为提问者说他是F#的新手,也许值得迭代一点。 首先,使用两个参数定义一个函数:
let interpreteSport (sport:string) (player:int) =
在F#中,没有可选参数的概念与C#中存在的相同意义,因此如果您声明一个具有两个参数的函数,并且您想要调用它并获得其返回值,则必须提供所有参数您在其定义中输入的参数。 所以在你的匹配表达式的第一个分支中,当你写:
:? Individual -> interpretSport(sport.Name)
你正在犯一个错误,只将一个参数传递给一个需要两个参数的函数。
但是等等! 为什么编译器没有提醒你一个错误,说你正在调用带有一个参数的函数,当它需要两个时? 因为事实证明你所写的内容,即使它没有像你所认为的那样调用interpreteSport函数,它也是F#中完美有效的表达式。 它返回的是一个称为“部分应用函数”的表达式,即一个已经接收到其第一个参数并正在等待另一个参数的函数。 如果将这样的表达式的结果赋值给一个值,那么就说:
let parzFun = interpretSport sport.Name
然后您可以在代码中传递此值,并且当您准备提供缺少的参数时,请按以下方式对其进行评估:
let result = parzFun 1
这就是编译器在谈到'int -> unit'
时告诉你的内容:F#中的函数签名以这种形式给出:
a -> b -> c -> d -> retval
,其中a,b,c,d等是参数的类型,retVal是返回值。
你的interpreteSport函数有一个签名:string -> int -> unit
,其中unit
是特殊类型,意思是“没有价值”,类似于C#void,但是区别在于单位是一个表达式你可以正确地赋值,而void只是一个关键字,你不能在C#中将变量赋值为void。
好的,所以,当你调用你的函数只传递第一个参数(一个字符串)时,你得到的是一个类型int -> unit
的表达式,这是另一个期望的函数和整数并返回单位。
因为此表达式位于匹配表达式的一个分支中,并且因为匹配表达式的所有分支必须返回相同的类型,所以其他2个分支也应该返回int -> unit
函数,它不是,这解释了你的第二个错误。
稍后会详细介绍,但在此之前,我们必须查看编译器报告的第一个错误,由此行代码引起:
:? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
在这里,您认为您正在使用2个参数调用函数,但实际上并非如此:当您在括号中放入2个值(用逗号分隔)时,您创建的是元组,即由单个值组成的值两个或多个值。这就像你只是再次传递第一个参数,但现在使用了错误的类型:你函数的第一个参数是一个字符串,而你传递一个元组:('a *'b)是F#表示元组的方式:表示由类型'a(泛型,在您的情况下为字符串)中的值和另一个类型为'b(泛型,在您的情况下为整数)中的值组成的单个值。 要正确调用您的函数,您必须调用它:
:? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
但即使你限制自己进行这种修正,你也会得到第二个错误,因为记住,匹配的第一个表达式会返回一个部分应用的函数,所以int -> unit
(一个需要整数的函数)当你的第二个和第三个表达式现在是unit
类型时,它会返回一个单位),因为它们实际上调用了两个返回unit
(interpreteSport
和printfn
)的函数。要完全修复代码,就像在其他答案中已经说过的那样,必须为第一次调用提供缺少的整数参数,所以:
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport sport.Name 1
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
| _ -> printfn "not a sport"
答案 1 :(得分:5)
你的函数interpretSport
有两个参数,但你第一次调用它只有一个。试着这样称呼它:
| :? Individual -> interpretSport sport.Name 1
此外,第二个调用使用了tupled参数,但声明函数采用curried参数。试着这样称呼它:
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
答案 2 :(得分:5)
如果这是一个F#学习练习,那么最好完全避免类和继承。基本的惯用F#类型是记录和受歧视的联盟。
我的代码的意图根本不清楚,但我试图重构以删除类的使用:
SELECT 10 as price
UNION ALL
SELECT ('{"price":2}'::jsonb->>'price')::int as price;
答案 3 :(得分:3)
您的代码存在一些小问题。最明显的是在matchSport中,您使用参数元组以未经验证的样式调用interpretSport。电话应该如下:
Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
然而,这是一个问题,因为在模式匹配的第一种情况下,您只使用一个参数调用interpretSport
,因此您部分应用它并获得类型int -> unit
,但是当你在第二个案例中完全应用它时,你得到unit
,当然所有类型的模式匹配案例都必须匹配。最便宜的解决方案是在第一个案例中为您的通话添加1
,如下所示:
Individual -> interpretSport sport.Name 1
但是你可能想要使用之前绑定的运动(可能在你给出的列表中作为参数)来进行检查。一般来说(在函数式编程和其他地方)硬编码很多字符串是一个坏主意,你可能想要做某种关联List,或者体育地图到Ranks,然后折叠体育列表并匹配当找到个人或团队时,然后打印地图为您提供的任何内容。这将更短,更具可扩展性。