F# Zen – ROT13


Below is a primitive implementation of ROT13 / Ceasar Cipher in F#. In short it is a simple encryption algorithm that works by ‘shifting’ each letter 13 places. So an ‘a’ becomes an ‘n’, a ‘b’ becomes an ‘o’, and so on. To decrypt the text you simply move 13 places in reverse.

We can do this in F# easily using function composition. Given a string, which is also a sequence of characters, we pass it to Array.of_seq so we have an array of characters. This will enable us to replace each character with its encrypted version. Next we map each character to our encryption function, which I’ll go over next. Finally, we take our array of encrypted characters and return a new string.

To actually do the encryption, we will compose three functions together. int, will convert the character to its integer representation. "(+) 13" is a curried version of the (+) function, so it adds 13 to its argument. And then we compose that with the char function, which will convert the integer result to a character.

#light

(**
 * ROT13 in F#
 * 
 * 1. Convert the sequence of chars (string) to an array of chars
 * 2. For each character do the following:
 *    - Convert the character to an integer
 *    - Add 13 to the integer value of the character (by currying (+))
 *    - Convert the integer to a character
 * 3. Create a new string based off the encrypted characters
 *)
 
let EncryptText (text : string) = 
    text
    |> Array.of_seq
    |> Array.map (int >> ((+) 13) >> char)
    |> (fun chars -> new string(chars))

let DecryptText (text : string) = 
    text
    |> Array.of_seq
    |> Array.map (int >> ((+) -13) >> char)
    |> (fun chars -> new string(chars))

let Test message =
    let encrypted = EncryptText message
    let decrypted = DecryptText encrypted

    printfn "Original Message  = %s" message
    printfn "Encrypted Message = %s" encrypted
    printfn "Decrypted Message = %s" decrypted
    
Test "The quick fox jumped over the lazy dog"

Comments (12)

  1. I like how F# makes the algorithm be so simple and elegant, and I didn’t know about this super simple way of casting chars into ints, thanks!

    I recently made a F# implementation of Bruce Schneier’s Solitaire encryption algorithm, you might want to check it out: http://www.sergimansilla.com/blog/?p=24

    Your opinion will be really appreciated 🙂

    Thanks for your articles!

  2. I feel uneasy about nitpicking like this, but it is even simpler via module [b]Microsoft.FSharp.Core.String[/b]’s [b]map[/b] function:

    [code]let encryptText (s:string) =

     s |> String.map (int >> ((+) 13) >> char)

    let decryptText (s:string) =

     s |> String.map (int >> ((+) -13) >> char)

    [/code]

    And thanks for the first practical (and beautifully elegant) use I’ve seen so far of fct composition — I’m sure there are more to be discovered.

    And, officially, everything about F# is tremendous from the lang design to the docs to shipping the source code.  You guys have set the new standard for combining high-level cs theory, real-world programmer productivity and exe performance.  After 20 years of professional programming (mostly C/C++/C# and various db systems), you guys have me excited about programming again.

    -Robert

    [i]"Lasting Peace and Happiness for [u][b]ALL[/b][/u] human beings."[/i]

  3. Carsten K. says:

    well I guess I give my 25cents too:

    You will see a lot of ROT13 "encrypted" messages in the usenet (to "hide" a solution, mark a spoiler etc.). In order to make your code really work there you will have to take care of some cases:

    1) normaly only [a-z], [A-Z] gets encrypted so a->n, A->N but !->! for example.

    2) You don’t need a decrypt-function in those cases 😉 – it’s the same as the encryption function

  4. At 13 characters, you’re already halfway through the alphabet. Meaning you could have just 1 function for encrypting and decrypting.

  5. ChrSmith says:

    @Patrick,

    True, but if and only if you modulo the integer value of each character with 26. Since I’m blindly adding 13, ‘z’ becomes something outside the typical ASCII plane…

    That’s exactly why I didn’t clame this ‘was’ an exact implementation of ROT13, but equivocated with ‘primitive implementation of ROT13 / Ceasar Cipher’.

    But yes, you are right. If you did the extra work you would only need one function for encrypting and decrypting.

  6. How does one "read" the line:

      Array.map (int >> ((+) 13) >> char)

    I like to apply a natural language to something I’m trying to learn, but I’m not sure of the correct way to say what this is doing.

  7. ChrSmith says:

    That is the beauty of function composition 🙂

    I’ll probabaly need to devote an entire post to concept later, but in short:

    Array.map takes a function which converts the array element to some new value. So in the context of ROT13 transforms a char to a new char.

    [int >> (+) 13 >> char] is actually three functions glued together using the function composition operator (>>).

    [int] takes an input and converts it to an integer, so ‘A’ is converted to 65.

    [(+) 13] is the (+) function with the first parameter specified as 13, so it is a function that takes an input of an integer and returns 13 plus that integer.

    [char] takes an input and converts it to a character. So 65′ is converted to ‘A’.

    By composing those three functions [int >> (+) 13 >> char] the result is a new function that takes anything, converts it to an integer, adds 13, and converts that to a character.

    So when applied via Array.map it encrypts the input string.

    Function composition is one of the core conepts of functional programming, but definitely requires a bit of time to wrap your head around.

  8. Thanks for the explanation. It doesn’t look like function composition from what I know of the subject. Knowing that ">>" is the function composition operator makes it really easy to read the line now, thanks again.

  9. Jay Hugard says:

    This doesn’t show clever use of function composition (very cool, by the way), but it does provide a traditional rot13 implementation:

    let rot13 =

       let rot b c = (int c – int b + 13) % 26 + int b |> char

       String.map (function

                    | ‘A’..’Z’ as c -> rot ‘A’ c

                    | ‘a’..’z’ as c -> rot ‘a’ c

                    | c -> c )

  10. Frederico Pessoa says:

    Summing all cents:

    let rot13 s =

       let rotc = function

           | i when 97 <= i && i <= 122 -> (i – 84) % 26 + 97

           | i when 65 <= i && i <= 90 -> (i – 52) % 26 + 65

           | i -> i

       s |> String.map (int >> rotc >> char)

  11. Frederico Pessoa says:

    And I do miss python 0 <= x <= 100 construct…

Skip to main content