3
\$\begingroup\$

this is my first F# program, very simple concept but took me a few minutes to get it. I'm new to functional programming so I'd appreciate if you could have a look at and comment the code.

Suggest changes or any code smells?

module FSharpFun.PrintSentenceInLines

open System

let printWord w = printfn "%s" w
let printEveryWord = Array.map printWord
let splitIntoWords (s:String) = s.Split ()

// Read a line and print each word in a new line
[<EntryPoint>]
let main _ =
    Console.ReadLine () |> splitIntoWords |> printEveryWord |> ignore
    0
    
    
\$\endgroup\$
3
  • \$\begingroup\$ Array.iter instead of Array.map is a more appropriate here. Then we can eventually get rid of the last |> ignore. Finally and less important, we could inline printEveryWord because Array.iter printWord reads well enough. \$\endgroup\$ May 14 at 18:09
  • \$\begingroup\$ Just made the changes, it looks much better, I will read up a bit to understand why I didn't need the last |> ignore. Now that I've made the change this program looks even more basic, but that's ok. Baby steps :) Thanks a lot \$\endgroup\$
    – Santanor
    May 15 at 9:33
  • 1
    \$\begingroup\$ When you use Array.map the result is another array, of Units, one per each word you printed. That array needs to be ignore-ed since it's a value and the F# compiler likes its values to be "attached" to something. Opting for Array.iter gives you a single Unit as output, and Unit is a sort of "no data value", so the compiler ignores it on its own. (This is, of course, very figurative, but it's "correct enough" to explain why iter is better, more correct even). And, as Romain said, just go with ... |> Array.iter (fun w -> printfn $"%s{w}") \$\endgroup\$ Jun 9 at 13:56
3
\$\begingroup\$

Sometimes the code itself reads just as simply as a name for a function, so you could inline all of this and reduce the urge for the reader to jump up to a function definition to check what exactly a function is doing:

splitIntoWords

vs

fun s -> s.Split()

And then:

printEveryWord

vs

Array.iter (printfn "%s")

In this case, I'd want to check the function just to understand there wasn't magic around what exactly a 'word' is. If the code is inlined, I can see it's just based on string splitting.

let main _ =
    Console.ReadLine()
    |> fun s -> s.Split()
    |> Array.iter (printfn "%s")

printfn "%s" is itself a function which expects a string

> printfn "%s";;
val it : (string -> unit) = <fun:it@1>

So it works great as is to pass into Array.iter

\$\endgroup\$
1
  • \$\begingroup\$ I really like this solution, thank you! \$\endgroup\$
    – Santanor
    Jul 23 at 13:32

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.