开发者

F# Matching mutable object (string)

Here is the full code so far:

module clean
#light
open System
open System.IO
let pause() = Console.ReadLine()
let drive = System.IO.Directory.GetDirectoryRoot(System.IO.Directory.GetCurrentDirectory())
printfn "You're using the %s drive.\n\n" drive

let game1 = "Assassin's Creed"
let game2 = "Crysis"
let game3 = "Mass Effect"

let local1 = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\"
let local2 = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\"
let local3 = "\%USERPROFILE\%\\Documents\\BioWare\\Mass Effect\\Save\\"

let roam1 = drive + "Saves\\Abraxas\\" + game1 + "\\"
let roam2 = drive + "Saves\\Abraxas\\" + game2 + "\\"
let roam3 =开发者_高级运维 drive + "Saves\\Abraxas\\" + game3 + "\\"




let rec getGame() =
  printfn "Which Game?\n\n   1.%s\n   2.%s\n   3.%s\n\n" game1 game2 game3
  match Int32.TryParse(stdin.ReadLine()) with
  | true,1 -> game1
  | true,2 -> game2
  | true,3 -> game3
  | _ ->
     printfn "You did not enter a valid choice."
     let _ = pause()
     Console.Clear()
     getGame()

let mutable gameprint = getGame()
printf "You have chosen %s\n\n" gameprint

let roaming =
  match gameprint with
  | game1 -> roam1
  | game2 -> roam2
  | game3 -> roam3
  | _ -> "test"

printf "Roaming set to %s\n\n" roaming

let local =
  match gameprint with
  | game1 -> local1
  | game2 -> local2
  | game3 -> local3
  | _ -> "test"

printf "Local set to %s\n\n" local

printf "Check gameprint  %s" gameprint

In the section that sets the roaming and local objects, it is telling me that it will never match with anything other than 'game1'.

I did the 'printf' to check before and after matching with the local and roaming objects... The gameprint shows correctly in both of the printf commands, but doesn't match to anything other than game1... I'm not sure where I made the mistake.


Two things.

  1. In F#, bindings can be shadowed. In particular, within your match, when you use game1, game2, and game3 in patterns, you are actually declaring new bindings with these names. Therefore, the first pattern will always match, and will just assign whatever value you are trying to match against it to the new binding game1 before evaluating the right hand side.

    One way to work around this is to declare your gameN bindings with the [<Literal>] attribute (but note that they must also start with capital letters to work as constants):

    [<Literal>] let Game1 = "Assassin's Creed"

    Now you can use Game1 in a pattern match and it will work as you expect.

  2. You may be aware of this, but you're not actually updating the gameprint binding anywhere anyway, so it's going to be set to the same value throughout your program and there is no point to its being mutable.


See F# matching with two values for an explanation.

When comparing against a few non-literal values, I'd just use an if-then-else

if gameprint = game1 then ...
elif gameprint = game2 then ...
...


Maybe something a little more like this would allow you to make it more extensible (if you populate the list of games at runtime) ... sorry the codes a little rushed I'm trying to get ready for work:

open System 
type Game = {Title:string; local:string; roam:string}

let game1 = {
    Title= "Assassin's Creed"; 
    local = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\"; 
    roam = "Saves\\Abraxas\\\Assassin's Creed\\"
}
let game2 = {
    Title= "Crysis"; 
    local = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\"; 
    roam = "Saves\\Abraxas\\\Crysis\\"
}
let games = [game1; game2]
let printGamelListItem i g = printfn "%i: %s" i g.Title

let printChoice() = 
    printfn "Which Game?\n"
    games |> List.fold (fun acc g -> 
                            printGamelListItem acc g 
                            acc+1) 1
    |> ignore

let rec getGame() = 
    printChoice()
    match Int32.TryParse(Console.ReadLine()) with
    |true, x  when x <= games.Length -> games.[x-1]
    | _ ->
        printfn "You did not enter a valid choice."
        let _ = Console.ReadLine()
        Console.Clear()
        getGame()

let selection = getGame()
printfn "Roaming set to: %s" (selection.roam)
printfn "Local set to: %s" (selection.local)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜