Last active
August 29, 2015 14:00
-
-
Save adityagodbole/11152703 to your computer and use it in GitHub Desktop.
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
from collections import namedtuple | |
from types import MethodType | |
def _init(self, *args, **kwargs): | |
if not self._typespec: | |
return | |
if len(self._fields) != len(self._typespec): | |
raise TypeError("Incorrect type in constructor") | |
for field, ts in zip(self._fields, self._typespec): | |
if ts and not isinstance(getattr(self, field), ts): | |
raise TypeError("Incorrect type in constructor") | |
def _extend(base, name, *args, **kwargs): | |
fields = base._fields + args | |
typespec = base._typespec + kwargs.pop('typespec', None) | |
argsdict = kwargs.copy() | |
argsdict.update({ 'typespec': typespec }) | |
return newtype(name, fields, **argsdict) | |
def newtype(name, *args, **kwargs): | |
typespec = kwargs.pop('typespec', None) | |
struct = namedtuple(name, *args, **kwargs) | |
struct.__init__ = MethodType(_init, None, struct) | |
struct.extend = MethodType(_extend, struct) | |
struct._typespec = typespec | |
return struct |
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
from records import newtype | |
# New immputable tuple type with rudimentary typecheck | |
Point = newtype('Point', 'x y', typespec=(int, int)) | |
# Extend an existing type | |
Vector = Point.extend('Vector', 'z', typespec=(int,)) | |
# Compose a new type out of existing | |
VectorE = newtype('VectorE', 'pt z', typespec=(Point, int)) | |
# Define functionality without the data (interface) | |
class Geom(object): | |
def distance2D(self): | |
return self.x + self.y | |
def distance3D(self): | |
return self.x + self.y + self.z | |
# "include" the Geom functionality as well as implement | |
# some new functionality | |
class VectorOps(Vector, Geom): | |
def show(self): | |
print "VectorOps: ", self.x, self.y, self.z | |
#p = Point(1, 2.0) # Raises typeerror | |
#v = Vector(1, 2, 3.0) # Raises typeerror | |
v = Vector(1, 2, 3) | |
print "Vector: ", v.x, v.y, v.z | |
ve = VectorE(Point(1,2), 3) | |
print "VectorE: ", ve.pt.x, ve.pt.y, ve.z | |
vo = VectorOps(1, 2, 3) | |
vo.xshow() | |
print "2D: ", vo.distance2D() | |
print "3D: ", vo.distance3D() | |
# This will cause an exception | |
vo.z = 10 |
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
$ python test.py | |
Vector: 1 2 3 | |
VectorE: 1 2 3 | |
VectorOps: 1 2 3 | |
2D: 3 | |
3D: 6 | |
Traceback (most recent call last): | |
File "test.py", line 30, in <module> | |
vo.z = 10 | |
AttributeError: can't set attribute |
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
This exercise is to demonstrate that assignment is not necessary | |
# for a general purpose language. Assignment creates local mutable state. | |
# While local state is necessary, it need not be mutable. | |
# Immutable local state can be implemented using functions | |
from records import newtype | |
from math import sqrt | |
Point = newtype('Point', 'x y', typespec=(int, int)) | |
# This is an example of a function which uses assignment | |
def _distances(pt1, pt2): | |
xdiff = pt1.x - pt2.x | |
ydiff = pt1.y - pt2.y | |
simpledist = xdiff + ydiff | |
fulldist = sqrt(xdiff ** 2 + ydiff ** 2) | |
return (simpledist, fulldist) | |
# This is the equivalent function without assignment | |
# Concept - local state can be achieved with closures | |
# and in some languages is implemented that way. | |
# In scheme let can be implemented as a macro using | |
# lambdas | |
def distances(pt1, pt2): | |
def dists(xdiff, ydiff): | |
def simpledist(): | |
return xdiff + ydiff | |
def fulldist(): | |
return sqrt(xdiff ** 2 + ydiff ** 2) | |
return (simpledist(), fulldist()) | |
return dists(pt1.x - pt2.x, pt1.y - pt2.y) | |
def main(p1, p2): | |
print distances(p1, p2) | |
print _distances(p1, p2) | |
main(Point(10, 10), Point(20, 20)) |
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
$ python localstate.py | |
(-20, 14.142135623730951) | |
(-20, 14.142135623730951) |
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
# This demostrates how we can model typeclasses or interfaces | |
# on top of our types | |
from records import newtype | |
from math import sqrt | |
Point = newtype('Point', 'x y', typespec=(int, int)) | |
# This class only defines behaviour | |
class Vector(object): | |
def magnitude(): | |
return sqrt(self.x ** 2 + self.y ** 2) | |
# Class Point "includes" the Vector behaviour | |
# We can say that Point "implements" Vector | |
class Point(Point, Vector): | |
pass | |
# Note that we have passed the type Vector, which is just | |
# an interface or a typeclass in the typespec. Below we | |
# construct a Segment using Point values. This is all cool :) | |
Segment = newtype('Segment', 'p1 p2', typespec=(Vector, Vector)) | |
class Segment(Segment): | |
def length(self): | |
def diffsq(x, y): | |
return (x - y) ** 2 | |
return sqrt(diffsq(self.p1.x, self.p2.x) + | |
diffsq(self.p1.y, self.p2.y)) | |
def main(p1, p2): | |
print Segment(p1, p2).length() | |
main(Point(10, 10), Point(20, 20)) |
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
$ python typeclasses.py | |
14.1421356237 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment