3
\$\begingroup\$

Here is my first try at F#. My only functional experience is from JS.

This program takes a path as an argument and presents the user with numbered subdirs in that path. The user then selects one of the subdirs by entering it's number and the program opens explorer with the newest subdir of the selected subdir.

Any comments will be greatly appreciated — shorter and better syntax, conversions to point-free style, structuring...

open System
open System.IO

let toDirWithCreationDate path =
    (path, Directory.GetCreationTime(path))

let getLatestSubDir =
    Seq.map toDirWithCreationDate
    >> Seq.sortByDescending snd
    >> Seq.head
    >> fst

let getNumberedSubDirTuples =
    let ints = Seq.initInfinite (fun n -> n + 1)
    Directory.GetDirectories
    >> Seq.sort 
    >> Seq.zip ints

let printDirMenu =
    Seq.iter (fun (a, b) -> printfn "%A %A" a b)

let openDir (dir:string) =
    ignore (System.Diagnostics.Process.Start(dir))

[<EntryPoint>]
let main argv = 
    let path = argv |> Seq.head
    let dirsSeq = getNumberedSubDirTuples path
    printDirMenu dirsSeq
    let dirNr = System.Console.ReadLine()
    let dir = 
        dirsSeq 
        |> Seq.tryFind(fun (a,b) -> a = int(dirNr))
    let latestSubdir = 
        match dir with
            | Some d -> Directory.GetDirectories (snd d) |> getLatestSubDir |> openDir
            | None -> printfn "Invalid input"
    0
\$\endgroup\$
  • 1
    \$\begingroup\$ Meta-advice: instead of focusing on syntax, focus on properties (e.g. purity, partiality, etc) \$\endgroup\$ – Mauricio Scheffer Aug 31 '16 at 21:31
1
\$\begingroup\$

I am not sure if I can summarize the changes I made better, but I made several refactorings and better error handling (when inputing a string, for example, your program crashed.) I also chose to make it zero-indexed, rather than 1-indexed, mostly to simplify the code.

open System
open System.IO

let getLatestSubDir = Seq.maxBy Directory.GetCreationTime // Refactored
let sortedSubDirs = Directory.GetDirectories >> Seq.sort // Refactored
let printDirMenu = 
    sortedSubDirs >> Seq.iteri (fun idx path -> printfn "%d %s" idx path)
let openDir (dir : string) = System.Diagnostics.Process.Start(dir) |> ignore

[<EntryPoint>]
let main argv = 
    let path = argv |> Seq.head
    printDirMenu path
    let input = System.Console.ReadLine()
    match Int32.TryParse(input) with
    | true, n -> 
        let dir = 
            path
            |> sortedSubDirs
            |> Seq.tryItem n
        match dir with
        | Some d -> 
            Directory.GetDirectories(d)
            |> getLatestSubDir
            |> openDir
        | None -> printfn "Invalid input"
    | _ -> printfn "Invalid input"
    Console.ReadKey() |> ignore
    0

It is definitely possible to factor the sorting so it is only done once, rather than twice in my code.

The code also crashes when the chosen folder doesn't have any sub folders.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.