Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Programming - Avoid mutable in match expression and changing int value

I just started programming functionally. My current tiny project to start would be a basic pokemon battle.

Code first, explanation follows.

let choosePokemon () =
    let mutable pokemon = DemoData.schiggy
    let msg = Console.ReadLine()
    match msg with
    | "Schiggy" -> pokemon <- DemoData.schiggy
    | "Pikachu" -> pokemon <- DemoData.pikachu
    | "Kleinstein" -> pokemon <- DemoData.kleinstein
    | "Karpador" -> pokemon <- DemoData.karpador 
    pokemon

I am currently asking people to enter the name of a Pokemon and if it matches a predefined set (Schiggy, Pikachu, Kleinstein or Karpador) it gives them the respective Pokemon. Alternatively it gives them the default Pokemon.

I am currently creating it before matching it with "let mutable pokemon = DemoData.schiggy". I don't want that. I just want to assign it based on its name.

If I could go without that line I'd avoid making it mutable, which is something I don't want anyways.

Additional question further down the line: When Pokemon attack each other their hp will decrease.

How can I avoid using a mutable int when facing a changing int value?

Thanks in advance :)

like image 910
Psyman2 Avatar asked Sep 01 '25 22:09

Psyman2


1 Answers

Just return the result from the match - there's no need to declare a variable:

let choosePokemon () =
    let msg = Console.ReadLine()
    match msg with
    | "Schiggy" -> DemoData.schiggy
    | "Pikachu" -> DemoData.pikachu
    | "Kleinstein" -> DemoData.kleinstein
    | "Karpador" -> DemoData.karpador

The function is still impure, though, since it performs I/O (Console.ReadLine)...

It's also partial, since it'll crash on any other input than the four strings being matched. Even misspellings and case mistakes are going to throw an exception.

A more robust pure function would be something like this:

let choosePokemon (input : string) =
    match input.Trim().ToUpperInvariant () with
    | "PIKACHU"    -> DemoData.pikachu
    | "KLEINSTEIN" -> DemoData.kleinstein
    | "KARPADOR"   -> DemoData.karpador
    | _            -> DemoData.schiggy

Contrary to the OP that performs I/O, this version is a pure function, since there's no non-deterministic behaviour. It's also total, since it returns schiggy as a default value.

To get the behaviour where you ask the user to input a value, compose the impure Console.ReadLine action with the pure choosePokemon function:

Console.ReadLine >> choosePokemon
like image 178
Mark Seemann Avatar answered Sep 03 '25 21:09

Mark Seemann