Skip to content

Instantly share code, notes, and snippets.

@akimboyko
Created October 17, 2013 05:47
Show Gist options
  • Save akimboyko/7019648 to your computer and use it in GitHub Desktop.
Save akimboyko/7019648 to your computer and use it in GitHub Desktop.
Quiz from Functional Programming Principles in Scala by Martin Odersky, lecture 4.2 implemented on F# with unittests
//Provide an implementation of the abstract class Nat that represents non-negative integers
//
//Do not use standard numerical classes in this implementation.
//Rather, implement a sub-object and sub-class:
//
//class Zero : Nat
//class Succ(n: Nat) : Nat
//
//One of the number zero, then other for strictly positive numbers.
namespace Nat
module Nat =
open System
type Nat =
abstract member IsZero : unit -> bool
abstract member Predecessor : unit -> Nat
abstract member Successor : unit -> Nat
abstract member Plus : Nat -> Nat
abstract member Minus : Nat -> Nat
type Succ(prev: Nat) =
interface Nat with
member this.IsZero() = false
member this.Predecessor() = prev
member this.Successor() = new Succ(this) :> Nat
member this.Plus(that) =
match that with
| :? Succ -> (this :> Nat).Successor().Plus(that.Predecessor())
| _ -> this :> Nat
member this.Minus(that) =
match that with
| :? Succ -> (this :> Nat).Predecessor().Minus(that.Predecessor())
| _ -> this :> Nat
override this.ToString() = prev.ToString() + "+"
let Zero = {
new Object() with
member this.ToString() = "0"
interface Nat with
member this.IsZero() = true
member this.Predecessor() = raise(ArithmeticException())
member this.Successor() = new Succ(this) :> Nat
member this.Plus(that) =
match that with
| :? Succ -> that
| _ -> this
member this.Minus(that) =
match that with
| :? Succ -> raise(ArithmeticException())
| _ -> this
}
namespace Nat.Tests
module Testing =
open Xunit
open FsUnit.Xunit
open Nat
[<Fact>]
let ``Zero has IsZero true`` () =
Nat.Zero.IsZero() |> should be True
[<Fact>]
let ``Successor has IsZero false`` () =
let successorOfZero = new Nat.Succ(Nat.Zero) :> Nat.Nat
(successorOfZero).IsZero() |> should be False
[<Fact>]
let ``Zero has no predecessor`` () =
(fun () -> Nat.Zero.Predecessor() |> ignore) |>
should throw typeof<System.ArithmeticException>
[<Fact>]
let ``Zero has successor other then Zero`` () =
Nat.Zero.Successor() |> should not' (be sameAs Nat.Zero)
[<Fact>]
let ``First natural number has successor other then itself`` () =
let firstNaturalNumber = new Nat.Succ(Nat.Zero) :> Nat.Nat
firstNaturalNumber.Successor() |> should not' (sameAs firstNaturalNumber)
[<Fact>]
let ``Predcesor for first natural number is Zero``() =
let firstNaturalNumber = new Nat.Succ(Nat.Zero) :> Nat.Nat
firstNaturalNumber.Predecessor() |> should be (sameAs Nat.Zero)
[<Fact>]
let ``Predcesor for 2 is 1``() =
let nat1 = new Nat.Succ(Nat.Zero) :> Nat.Nat
let nat2 = nat1.Successor()
nat2.Predecessor() |> should be (sameAs nat1)
[<Fact>]
let ``Zero to return string interpretation "0"``() =
Nat.Zero.ToString() |> should equal "0"
[<Fact>]
let ``Two to return string interpretation "0++"``() =
let nat2 = (new Nat.Succ(Nat.Zero) :> Nat.Nat).Successor()
nat2.ToString() |> should equal "0++"
[<Fact>]
let ``Zero plus Zero should be Zero``() =
Nat.Zero.Plus(Nat.Zero) |> should be (sameAs Nat.Zero)
[<Fact>]
let ``Zero plus non-Zero should be non-Zero itself``() =
let nat1 = new Nat.Succ(Nat.Zero) :> Nat.Nat
let nat2 = nat1.Successor()
Nat.Zero.Plus(nat2) |> should be (sameAs nat2)
[<Fact>]
let ``Zero minus Zero should be Zero``() =
Nat.Zero.Minus(Nat.Zero) |> should be (sameAs Nat.Zero)
[<Fact>]
let ``Zero minus non-Zero should raise ArithmeticException``() =
let nat2 = (new Nat.Succ(Nat.Zero) :> Nat.Nat).Successor()
(fun () -> Nat.Zero.Minus(nat2) |> ignore) |>
should throw typeof<System.ArithmeticException>
[<Fact>]
let ``Two plus Zero should be Two``() =
let one = new Nat.Succ(Nat.Zero) :> Nat.Nat
let two = one.Successor()
two.Plus(Nat.Zero) |> should be (sameAs two)
[<Fact>]
let ``One plus Two should be Three``() =
let one = new Nat.Succ(Nat.Zero) :> Nat.Nat
let two = one.Successor()
let three = two.Successor()
one.Plus(two).ToString() |> should equal (three.ToString())
[<Fact>]
let ``Two minus Zero should be Two``() =
let one = new Nat.Succ(Nat.Zero) :> Nat.Nat
let two = one.Successor()
two.Minus(Nat.Zero) |> should be (sameAs two)
[<Fact>]
let ``Three minus One should be Two``() =
let one = new Nat.Succ(Nat.Zero) :> Nat.Nat
let two = one.Successor()
let three = two.Successor()
three.Minus(one).ToString() |> should equal (two.ToString())
[<Fact>]
let ``Two minus Three should raise ArithmeticException``() =
let one = new Nat.Succ(Nat.Zero) :> Nat.Nat
let two = one.Successor()
let three = two.Successor()
(fun () -> two.Minus(three)|> ignore) |>
should throw typeof<System.ArithmeticException>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment