Skip to content

Instantly share code, notes, and snippets.

@ploeh
Created May 15, 2015 18:37
Show Gist options
  • Save ploeh/4f873315fc556f7672f1 to your computer and use it in GitHub Desktop.
Save ploeh/4f873315fc556f7672f1 to your computer and use it in GitHub Desktop.
F# readability test.
let nerdCapsToKebabCase (text : string) =
let charToString index c =
let s = c.ToString().ToLower()
match index, Char.IsUpper c with
| 0, _ -> s
| _, true -> "-" + s
| _ -> s
text |> Seq.mapi charToString |> String.concat ""
@blair55
Copy link

blair55 commented May 15, 2015

Yes

@blacktaxi
Copy link

Yep

@iskeld
Copy link

iskeld commented May 15, 2015

Yes
The only thing I don't like is the "charToString" name. It is confusing, because it's doing something more than a simple char -> string conversion (also, is the "string" type important here?). Can't think of any good alternative though ;)

@CraigStuntz
Copy link

Yes, I can read it, but I agree with @iskeld regarding charToString. My suggestion would be addSkewer :)

@lobrien
Copy link

lobrien commented May 15, 2015

Yes, readable.

@torbonde
Copy link

Yes.

@theimowski
Copy link

Yes, however it took a moment for me to get it

@ploeh
Copy link
Author

ploeh commented May 15, 2015

@CraigStuntz, I totally buy the addSkewer suggestion 👍

@Rickasaurus, I also see the point in explicitly spelling out the booleans.

Now it looks like this:

let nerdCapsToKebabCase (text : string) = 
    let addSkewer index c =
        let s = c.ToString().ToLower()
        match index, Char.IsUpper c with
        | 0, _ -> s
        | _, true -> "-" + s
        | _, false -> s
    text |> Seq.mapi addSkewer |> String.concat ""

@mqsoh
Copy link

mqsoh commented May 15, 2015

Readable for me and I've never looked at F# before.

@yuyoyuppe
Copy link

Yes

@baronfel
Copy link

Yes

@isaacabraham
Copy link

Yes and no :-) Yes, I could read through it and understand what it was doing, so I suppose it was adequately readable. However, I couldn't intuit the intent of the code instantly, which is something I try to do, particularly for smallish functions like this - I had to do a small mental map of what each of the match clauses represented. I would've probably renamed the lower case value from "s" to something more meaningful (or removed the binding completely and just placed the same code in both branches), and possibly have created an active pattern to encapsulate the logic e.g.

let nerdCapsToKebabCase (text : string) = 
    let (|FirstLetter|UpperCase|LowerCase|) (index, c) =
        match index, Char.IsUpper c with
        | 0, _ -> FirstLetter
        | _, true -> UpperCase
        | _ -> LowerCase        

    let charToString index c =
        let s = c.ToString().ToLower()
        match index, c with
        | FirstLetter | LowerCase -> s
        | UpperCase -> "-" + s

    text |> Seq.mapi charToString |> String.concat ""

@vasily-kirichenko
Copy link

I completely agree with @Rickasaurus about efficiency, but I prefer to use more functional approach (sort of, since StringBuilder is mutable anyway):

open System
open System.Text
open FSharpx.TimeMeasurement

let nerdCapsToKebabCase (text : string) = 
    let addSkewer index c =
        let s = c.ToString().ToLower()
        match index, Char.IsUpper c with
        | 0, _ -> s
        | _, true -> "-" + s
        | _, false -> s
    text |> Seq.mapi addSkewer |> String.concat ""

let nerdCapsToKebabCase' (text: string) = 
    text.ToCharArray() |> Array.foldi (fun (sb: StringBuilder) i c ->
        if i > 0 && Char.IsUpper c then sb.Append "-" |> ignore
        sb.Append (Char.ToLowerInvariant c))
        (StringBuilder()) |> string

let str = "UaBcDeFgH12345aBcDeFaBcDeFgH12345aBcDeF"

compareTwoRuntimes
    1000000
    "Ploeh" (fun _ -> nerdCapsToKebabCase str)
    "Me" (fun _ -> nerdCapsToKebabCase' str)
Ploeh 0.010262ms
Me 0.002114ms
Ratio:  4.854304636

@giacomociti
Copy link

Yes, maybe some naming adjustment may help but I find it readable the overall code structure

@cbowdon
Copy link

cbowdon commented May 15, 2015

Yes, but I feel in general top level functions should have return types for readability. It's not always obvious from the name (although it is here).

@jarlestabell
Copy link

Yes. But I agree with @isaacabraham, his extra separation of concerns makes this kind of code slightly faster to intuit if the concepts involved (in this case kebab-case) isn't known to the reader beforehand.

@rojepp
Copy link

rojepp commented May 15, 2015

Yes, readable, but distracting for me. This looks like something I could write just to get something working quickly when I'm really thinking about another problem. When reading, I keep getting distracted by the inefficiencies and will try to fix them in my head before moving on. :)

@blair55
Copy link

blair55 commented May 16, 2015

@bogdangaliceanu
Copy link

Yes, it is readable. After seeing @isaacabraham 's active patterns approach I kind of like that more, but regardless, the original is clear enough.

@aschlapsi
Copy link

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment