snippetMinor
Kata: Natural Sort
Viewed 0 times
sortkatanatural
Problem
I am choosing to learn F# for my own enjoyment. I am getting to the point where concepts of F# seem to be pretty easy, but understanding some of the whys and whens is a bit harder.
Before I get into the code and the explanation, let me put my question up front. I am asking where can I find better advice on formatting F# code for readability? Or can someone give me a few guiding tips based off of the example given below?
So what are the best practices for code format and file layout?
Now to the explanation of the code.
I have started practicing coding Kata's in F# just to allow me to flex the language a little. The following program is an implementation of a natural sort. This was my first attempt to solving the problem in a TDD fashion in F#, as such I chose to forgo any framework as I did not want to deal with figuring out how to use any of them and not break the functional paradigm.
So the code below carries a light weight unit test framework.
Here is the code for the natural sort:
```
namespace Katas
open System.Linq
module NaturalSortKata =
exception InvalidException of string
type Comparison =
| Equal
| Lesser
| Greater
static member Compare x y =
if x = y then
Equal
elif x > y then
Greater
else
Lesser
type ChunckType =
| NumberType
| StringType
| Unknown
static member GetType (c : char) =
if System.Char.IsDigit(c) then
NumberType
else
StringType
member this.Compare other =
match other with
| ty when ty = this -> Equal
| Unknown -> Lesser
| NumberType when this = Unknown -> Greater
| NumberType -> Lesser
| StringType -> Greater
let natualCompare (left : s
Before I get into the code and the explanation, let me put my question up front. I am asking where can I find better advice on formatting F# code for readability? Or can someone give me a few guiding tips based off of the example given below?
So what are the best practices for code format and file layout?
Now to the explanation of the code.
I have started practicing coding Kata's in F# just to allow me to flex the language a little. The following program is an implementation of a natural sort. This was my first attempt to solving the problem in a TDD fashion in F#, as such I chose to forgo any framework as I did not want to deal with figuring out how to use any of them and not break the functional paradigm.
So the code below carries a light weight unit test framework.
Here is the code for the natural sort:
```
namespace Katas
open System.Linq
module NaturalSortKata =
exception InvalidException of string
type Comparison =
| Equal
| Lesser
| Greater
static member Compare x y =
if x = y then
Equal
elif x > y then
Greater
else
Lesser
type ChunckType =
| NumberType
| StringType
| Unknown
static member GetType (c : char) =
if System.Char.IsDigit(c) then
NumberType
else
StringType
member this.Compare other =
match other with
| ty when ty = this -> Equal
| Unknown -> Lesser
| NumberType when this = Unknown -> Greater
| NumberType -> Lesser
| StringType -> Greater
let natualCompare (left : s
Solution
Your code formatting is very readable. The minor issue is that you don't have to indent after
So what are the best practices for code format and file layout?
I think F# code formatting guidelines have very concrete suggestions on these issues.
There are a few small problems with your code:
-
In
-
In
-
Value
Here is reformatted version of
UPDATE:
After answering your question, I started developing a source code formatter for F#. More information can be found on Gihub.
Results from the tool or its companion formatting guideline can give you some hints for good formatting.
namespace declaration. I would choose to open module directly to save a level of indentation (see attached code later).So what are the best practices for code format and file layout?
I think F# code formatting guidelines have very concrete suggestions on these issues.
There are a few small problems with your code:
-
In
naturalCompare, you should move local functions to the top so the logic of the function is clear.-
In
compare, if you remove when in the last clause, you don't have to superficially throw an exception.-
Value
tests is more readable in the form of normal list declaration.let tests = [ test01; test02; test03; test04; test05; test06; test07; test08; test09; ]Here is reformatted version of
Katas.NaturalSortKata module. You could do the same for Katas.Testing.Tests.// 0) Declare module to save a level of indentation
module Katas.NaturalSortKata
open System.Linq
type Comparison =
| Equal
| Lesser
| Greater
static member Compare x y =
if x = y then
Equal
elif x > y then
Greater
else
Lesser
type ChunckType =
| NumberType
| StringType
| Unknown
static member GetType (c : char) =
if System.Char.IsDigit(c) then
NumberType
else
StringType
member this.Compare other =
match other with
| ty when ty = this -> Equal
| Unknown -> Lesser
| NumberType when this = Unknown -> Greater
| NumberType -> Lesser
| StringType -> Greater
let naturalCompare (left : string) (right : string) =
// 1) Move local functions on top
let fix str =
new System.String( str |> List.rev |> List.toArray )
let gatherChunck str =
let rec gather str acc =
match str with
| [] ->
let (ty, l) = acc
(ty, fix(l))
| fistLetter::rest ->
match acc with
| (ty, _) when ty = Unknown ->
let t = ChunckType.GetType(fistLetter)
gather rest (t, fistLetter :: [])
| (ty, l) when ty = ChunckType.GetType(fistLetter) ->
gather rest (ty, fistLetter::l)
| (ty, l) -> (ty, fix(l))
gather str (Unknown, [])
let rec compare (left : string) (right : string) =
if (not (left.Any())) || (not (right.Any())) then
match left.Length, right.Length with
| llen, rlen when llen = rlen -> Equal
| llen, rlen when llen > rlen -> Greater
| llen, rlen -> Lesser // 2) Remove superficial when guard
else
let lt, lChunk = left |> Seq.toList |> gatherChunck
let rt, rChunk = right |> Seq.toList |> gatherChunck
match lt.Compare rt with
| Equal ->
if lChunk = rChunk then
let lVal = left.Replace(lChunk, "")
let rVal = right.Replace(rChunk, "")
compare lVal rVal
else
match lt with
| NumberType ->
Comparison.Compare (System.Int64.Parse(lChunk)) (System.Int64.Parse(rChunk))
| _ ->
Comparison.Compare lChunk rChunk
| _ ->
lt.Compare(rt)
if left = right then
Equal
else
compare left rightUPDATE:
After answering your question, I started developing a source code formatter for F#. More information can be found on Gihub.
Results from the tool or its companion formatting guideline can give you some hints for good formatting.
Code Snippets
let tests = [ test01; test02; test03; test04; test05; test06; test07; test08; test09; ]// 0) Declare module to save a level of indentation
module Katas.NaturalSortKata
open System.Linq
type Comparison =
| Equal
| Lesser
| Greater
static member Compare x y =
if x = y then
Equal
elif x > y then
Greater
else
Lesser
type ChunckType =
| NumberType
| StringType
| Unknown
static member GetType (c : char) =
if System.Char.IsDigit(c) then
NumberType
else
StringType
member this.Compare other =
match other with
| ty when ty = this -> Equal
| Unknown -> Lesser
| NumberType when this = Unknown -> Greater
| NumberType -> Lesser
| StringType -> Greater
let naturalCompare (left : string) (right : string) =
// 1) Move local functions on top
let fix str =
new System.String( str |> List.rev |> List.toArray )
let gatherChunck str =
let rec gather str acc =
match str with
| [] ->
let (ty, l) = acc
(ty, fix(l))
| fistLetter::rest ->
match acc with
| (ty, _) when ty = Unknown ->
let t = ChunckType.GetType(fistLetter)
gather rest (t, fistLetter :: [])
| (ty, l) when ty = ChunckType.GetType(fistLetter) ->
gather rest (ty, fistLetter::l)
| (ty, l) -> (ty, fix(l))
gather str (Unknown, [])
let rec compare (left : string) (right : string) =
if (not (left.Any())) || (not (right.Any())) then
match left.Length, right.Length with
| llen, rlen when llen = rlen -> Equal
| llen, rlen when llen > rlen -> Greater
| llen, rlen -> Lesser // 2) Remove superficial when guard
else
let lt, lChunk = left |> Seq.toList |> gatherChunck
let rt, rChunk = right |> Seq.toList |> gatherChunck
match lt.Compare rt with
| Equal ->
if lChunk = rChunk then
let lVal = left.Replace(lChunk, "")
let rVal = right.Replace(rChunk, "")
compare lVal rVal
else
match lt with
| NumberType ->
Comparison.Compare (System.Int64.Parse(lChunk)) (System.Int64.Parse(rChunk))
| _ ->
Comparison.Compare lChunk rChunk
| _ ->
lt.Compare(rt)
if left = right then
Equal
else
compare left rightContext
StackExchange Code Review Q#20955, answer score: 6
Revisions (0)
No revisions yet.