Created
October 17, 2013 05:47
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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 | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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