F#

What’s this? #

Notes on F# as I learn features. This sample, I’ve created a program that counts repeating charaters in a string. I break it down to Managers, Engines, Contracts so that it somewhat follows the IDesign nomenclature. Since this is my first foray into F#, this will likely not be a great example, but is more of a testing ground.

The Engines are called by the Managers. Contracts can be shared at all levels.

Getting intellisense to work #

I think adding .vscode\settings.json was needed to get code completion for built-in types.

{
    "FSharp.workspacePath": "./Fsharp.slnx",
}

Files #

The file tree for this code.

.
├── Alpha.Contracts
│   ├── Alpha.Contracts.fsproj
│   └── Types.fs
├── Alpha.Engines
│   ├── Alpha.Engines.fsproj
│   └── StringProcessor.fs
├── Alpha.Managers
│   ├── Alpha.Managers.fsproj
│   └── StringManager.fs
├── AppConsole
│   ├── AppConsole.fsproj
│   └── Program.fs
└── Fsharp.slnx

Types.fs #

namespace Alpha.Contracts

type LetterStat = {
    Letter: char
    Rank: int
    Count: int
}

StringProcessor.fs #

namespace Alpha.Engines

open Alpha.Contracts

module StringProcessor =
    let hello name fromTown =
        $"Hello %s{name}, from %s{fromTown}"

    let toCharList (input: string) =
        input.ToCharArray() |> Seq.toList

    let charAcc (input: char) (position: int) (acc: LetterStat list) =
        let foundChar = acc |> List.tryFind (fun c -> c.Letter = input)
        if foundChar = None then
            let newEntry = { Letter = input; Rank = position; Count = 1}
            acc @ [newEntry] // append
        else
            let newCount = foundChar.Value.Count + 1
            let updated = { foundChar.Value with Count = newCount }
            List.except [foundChar.Value] acc @ [updated]

    let findCharReferences (input: string) =
        let chars = toCharList input

        // fold is a fundamental concept.
        let output = chars |> List.fold (
            fun (idx: int, acc: LetterStat list) 
                curr -> idx + 1, charAcc curr idx acc) (0, [])
        snd output  // gets the second element of the tuple

StringManager.fs #

namespace Alpha.Managers

open Alpha.Engines

module StringManager =
    let hello name =
        printfn "Hello %s" 
        
    let findCharReferences = StringProcessor.findCharReferences

    let findFirstNonRepeatingChar input = 
        let result = StringProcessor.findCharReferences input
        result |> List.filter(fun x -> x.Count = 1) |> 
            List.sortBy(fun x -> x.Rank) |> List.tryHead            

Program.fs #

// For more information see https://aka.ms/fsharp-console-apps

open Alpha.Managers
open Alpha.Contracts

let inputStr = "tottoem"

let printOut (input : LetterStat list) = 
    input |> List.iter (fun item -> 
        printfn $"{item.Letter}: Count: {item.Count} Rank: {item.Rank} ")


let result = StringManager.findCharReferences(inputStr)
result |> printOut

printfn "----------"

let printOutSingle (input : option<LetterStat>) =
    if input.IsSome then 
        [input.Value] |> printOut
    else 
        printfn "no repeating chars found"

let result2 = StringManager.findFirstNonRepeatingChar(inputStr)
printOutSingle result2