Kev*_* II 4 f# functional-programming
我是F#的新手,并且一直在关注指南,试图让一段代码工作,但事实并非如此.
我通过继承创造单身和合作运动的类型.
然后我使用模式匹配来了解类型,如果是合作运动,也可以获得玩家数量.然后相应地排名.
但是,我一直在收到错误.我在这上面跟着微软的例子,我真的不明白错误.我没有函数式编程背景.
type Sport (name: string) =
member x.Name = name
type Individual(name: string) =
inherit Sport(name)
type Team(name: string, numberOfPlayers : int) =
inherit Sport(name)
member x.numberOfPlayers = numberOfPlayers
let MK = new Individual("Combate Mortal")
let SF = new Individual("Lutadores de Rua")
let Tk = new Individual("Tekken Chupa")
let MvC = new Team("Marvel Contra Capcom", 3)
let Dbz = new Team("Bolas do Dragao", 3)
let interpretSport (sport:string) (players:int) =
match sport with
| "Combate Mortal" -> printfn "Rank1"
| "Lutadores de Rua" -> printfn "Rank2"
| "Tekken Chupa" -> printfn "Rank3"
| "Bolas do Dragao" -> printfn "Rank4. No of players: %d " players
| "Marvel Contra Capcom" -> printfn "Rank5. No of players: %d" players
| _ -> printfn "not a sport in our list..."
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport(sport.Name)
| :? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
| _ -> printfn "not a sport"
matchSport(MK)
matchSport(SF)
matchSport(Tk)
matchSport(MvC)
matchSport(Dbz)
Run Code Online (Sandbox Code Playgroud)
问题已经得到解答,但因为提问者说他是F#的新手,也许值得迭代一点.首先,使用两个参数定义一个函数:
let interpreteSport (sport:string) (player:int) =
Run Code Online (Sandbox Code Playgroud)
在F#中,没有与C#中存在的可选参数概念相同的意义,因此如果您声明一个具有两个参数的函数,并且想要调用它并获取其返回值,则必须提供所有参数.在其定义中.所以在你的匹配表达式的第一个分支中,当你写:
:? Individual -> interpretSport(sport.Name)
Run Code Online (Sandbox Code Playgroud)
你正在犯一个错误,只将一个参数传递给一个需要两个参数的函数.
可是等等!为什么编译器没有提醒你一个错误,说你正在调用一个带有一个参数的函数? 因为事实证明你所写的内容,即使它没有像你所认为的那样调用interpreteSport函数,它也是F#中完美有效的表达式.它返回的是一个称为"部分应用函数"的表达式,即一个已经接收到其第一个参数并正在等待另一个参数的函数.如果将这样的表达式的结果赋值给一个值,让我们说:
let parzFun = interpretSport sport.Name
Run Code Online (Sandbox Code Playgroud)
然后,您可以在代码中传递此值,并且当您准备提供缺少的参数时,请按以下方式对其进行评估:
let result = parzFun 1
Run Code Online (Sandbox Code Playgroud)
这就是编译器在讨论时告诉你的内容'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)
Run Code Online (Sandbox Code Playgroud)
在这里,您正在考虑使用2个参数调用函数,但实际上并非如此:当您在括号中放入2个值(用逗号分隔)时,您创建的是元组,即由两个或更多个组成的单个值值.这就像你只是再次传递第一个参数,但现在使用了错误的类型:你函数的第一个参数是一个字符串,而你传递一个元组:('a*'b)是F#表示元组的方式:表示由类型'a(泛型,在您的情况下为字符串)中的值和另一个类型为'b(泛型,在您的情况下为整数)中的值组成的单个值.要正确调用您的函数,您必须调用它:
:? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
Run Code Online (Sandbox Code Playgroud)
但是即使你限制自己进行这种修正,你也会得到所有相同的第二个错误,因为,记住,你的匹配的第一个表达式返回一个部分应用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"
Run Code Online (Sandbox Code Playgroud)
你的函数interpretSport有两个参数,但你第一次调用它只有一个.试着像这样调用它:
| :? Individual -> interpretSport sport.Name 1
Run Code Online (Sandbox Code Playgroud)
此外,第二个调用使用了tupled参数,但声明该函数采用curried参数.试着像这样调用它:
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
Run Code Online (Sandbox Code Playgroud)
如果这是一个F#学习练习,那么最好完全避免类和继承.基本的惯用F#类型是记录和歧视的联合.
你的代码的意图根本不清楚,但我试图重构以删除类的使用:
type Players =
| Individual
| Team of numberOfPlayers:int
type Sport = { Name : string; Players : Players }
let MK = { Name = "Combate Mortal"; Players = Individual }
let SF = { Name = "Lutadores de Rua"; Players = Individual }
let Tk = { Name = "Tekken Chupa"; Players = Individual }
let MvC = { Name = "Marvel Contra Capcom"; Players = Team 3 }
let Dbz = { Name = "Bolas do Dragao"; Players = Team 3 }
let interpretSport (sport:Sport) =
let players =
match sport.Players with
| Individual -> ""
| Team numberOfPlayers -> sprintf ". No of players: %d" numberOfPlayers
let rank =
match sport.Name with
| "Combate Mortal" -> Some 1
| "Lutadores de Rua" -> Some 2
| "Tekken Chupa" -> Some 3
| "Bolas do Dragao" -> Some 4
| "Marvel Contra Capcom" -> Some 5
| _ -> None
match rank with
| Some r -> printfn "Rank%d%s" r players
| None -> printfn "not a sport in our list..."
Run Code Online (Sandbox Code Playgroud)