模式匹配铸造类型

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)

调用具有多个参数的函数时出现第一个错误:

打印时出现第2错误:

Fra*_*lue 7

问题已经得到解答,但因为提问者说他​​是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(interpreteSportprintfn)的函数.要完全修复代码,就像在其他答案中已经说过的那样,必须为第一次调用提供缺少的整数参数,因此:

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)


dum*_*ulo 5

你的函数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)


The*_*Fox 5

如果这是一个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)