Guest User

Untitled

a guest
Dec 21st, 2015
3,392
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 5.23 KB | None | 0 0
  1. (* ocaml's object system is quite unique and rarely used, despite it actually being pretty awesome
  2.  * I call it "statically typed duck typing" because that's what it is
  3.  *)
  4.  
  5. (* let's define a """class"""
  6.  * your basic example of a linked-list
  7.  *)
  8. let node (x, y) = object
  9.     method hd = x
  10.     method tl = y
  11.    
  12.     method nth n =
  13.         if n = 0 then
  14.             x
  15.         else
  16.             y#nth (n - 1)
  17.    
  18.     method length =
  19.         1 + y#length
  20. end
  21.  
  22. (* this isn't actually a class, this is a function called node that takes two arguments, and returns an object
  23.  * objects can easily be created anonymously, in this case we simply create an anonynmous object inside the function body
  24.  * this has methods and closes over the function arguments, this object is immutable
  25.  * as such, there is really no "this/self" keyword used in this approach
  26.  * this is your basic recursive implementation of a linked list's head, tail, indexing and length operations
  27.  *)
  28.  
  29. (*now,  the type of this constructor is quite something and automatically inferred by the compiler and statically checked:
  30.  *
  31.  * node :
  32.  * 'a * (< length : int; nth : int -> 'a; .. > as 'b) ->
  33.  *  < hd : 'a; length : int; nth : int -> 'a; tl : 'b >
  34.  *
  35.  * I've put it on two lines to make it clearer, the first is the input type. The second argument is the interesting one:
  36.  * < length : int; nth : int -> 'a; .. > as 'b
  37.  *
  38.  * this reads an object with:
  39.  * - a "length" method that returns an int
  40.  * - a "nth" method that takes an int and returns something of the same type as the first argument to node.
  41.  * - ANY FURTHER METHODS, this is what the dots indicate which is very important
  42.  *
  43.  * the quote before "a" means this is a type variable.
  44.  * This means that both instances of 'a can be any type, as long as they are the same one
  45.  *
  46.  * then the output type is our object. Which has all our methods,
  47.  * the most important one is that its "tl" method returns 'b, which we gave as a shorhand to the type of our second argument.
  48.  * obviously we return the tail we gave as second argument in tact.
  49.  *)
  50.  
  51. (* we wil also make a nil object
  52.  * this is not a function, OCaml just uses similar syntax to declare constants and functions
  53.  * note that we give it hd and tl and nth methods, but raise exceptions on them.
  54.  * This is done on purpose to give it the appropriate types.
  55.  * After all. Our "node" constructor demanded that its second argument implement the "nth" and "length" methods.
  56.  *)
  57. exception Empty_list
  58. let nil = object
  59.     method hd = raise Empty_list
  60.     method tl = raise Empty_list
  61.    
  62.     method nth n = raise Empty_list
  63.    
  64.     method length = 0
  65. end
  66.  
  67. (* so now we can make some linked lists
  68.  * probably not the most convenient syntax but you get the point
  69.  * this will all type check, all the numbers are the same type, which is what the implementation demanded
  70.  *)
  71. let int_list = node(0, node(1, node(2, node(3, nil))))
  72.  
  73. let () = Printf.printf "%d\n" int_list#length (* 3 *)
  74.  
  75. (* the constructors are polymorphic,
  76.  * the elements of the list  can be any type, as long as they are all the same type.
  77.  *)
  78. let string_list = node("zero", node("one", node("two", node("three", nil))))
  79.  
  80. let () = Printf.printf "%d\n" string_list#tl#length (* 2 *)
  81.  
  82. (* but this would be a static typing error,
  83.  *
  84.  * let hetero_list = node(0, node("one", node(2.0, node(`Three, nil))))
  85.  *)
  86.  
  87. (* now, here it gets interesting.
  88.  * Remember, all our implementation of the linked list wanted was
  89.  * that the second argument implemented "nth" and "length" correctly.
  90.  * so here's a fake parametic "structure" that is filled with factorials
  91.  *)
  92.  
  93. let weird_object  = object
  94.     val internal_array = [| 1,2,3,4 |]
  95.    
  96.     (* when we ask for the nth element, it in fact computes the factorial of said number *)
  97.     method nth n =
  98.         let rec factorial n =
  99.             if n = 0 then
  100.                 1
  101.             else
  102.                 n * factorial (n - 1)
  103.         in factorial n
  104.        
  105.    
  106.     method length = 60
  107. end
  108.  
  109. (* this array does not implement the hd and tl methods
  110.  * but our linked list implementation didn't ask for that for its second elements
  111.  * so, funnily enough, this works:
  112.  *)
  113.  
  114. let wtf_structure = node(0, node(4, weird_object))
  115.  
  116. (* and so does this
  117.  *)
  118. let () = Printf.printf "%d\n" wtf_structure#length   (* 62 *)
  119. let () = Printf.printf "%d\n" (wtf_structure#nth 8)  (* 720 *)
  120.  
  121. (* but say we wanted to implement map on our custom list:
  122.  *)
  123.  
  124. let rec map_obj f obj =
  125.     if obj#length = 0 then
  126.         obj
  127.     else
  128.         node (f obj#hd, map_obj f obj#tl)
  129.  
  130. (* so will this now work on our wtf_structure?
  131.  * No! because the type of this function is inferred by the implementation that the second argument is:
  132.  *
  133.  * (< hd : 'a; length : int; nth : int -> 'a; tl : 'b > as 'b)
  134.  *
  135.  * the "as 'b" part is important.
  136.  * It means that the "tl" method must in this case return an object which has all the methods listed there too.
  137.  * and that's something our "weird object" doesn't provide.
  138.  *)
  139.  
  140. (* conclusion
  141.  * OCaml's object system allows for "statically typed duck typing",.
  142.  * meaning that the type of an object is just its methods and thier types
  143.  * this system is surprisingly flexible. It statically checks if stuff quacks the right way.
  144.  *
  145.  * and yes, with explicit type annotations you can actually give a set of methods together a name
  146.  * and there are even classes if you want them
  147.  *)
Advertisement
Add Comment
Please, Sign In to add comment