[英]Haskell equivalent of data constructors in Python?
在Haskell中,我可以按如下方式定义二叉树:
data Bint a = Leaf a | Branch a (Bint a) (Bint a)
然后我可以对它进行一些操作如下:
height (Leaf a) = 1
height (Branch a l r) = 1 + (max (height l) (height r))
count (Leaf a) = 1
count (Branch a l r) = 1 + (count l) + (count r)
我知道Python在Haskell中没有相应的data
。 如果有,请告诉我。
那么,如何在Python中定义二叉树以及如何在其中实现上述两个函数呢?
我将在这里与Haskell进行类似的功能编程。 从某种意义上说,这不是非常“pythonic”。 特别是,它不是面向对象的。 不过,它仍然有用且干净。
数据类型是一个类。 具有多个数据构造函数的数据类型是一个类,其中包含有关如何构造它的额外信息。 当然,它需要一些数据。 使用构造函数确保所有树都合法:
class BinTree (object):
def __init__(self, value=None, left=None, right=None):
if left == None and right == None and value != None:
self.isLeaf = True
self.value = value
elif left != None and right != None and value == None:
self.isLeaf = False
self.value = (left, right)
else:
raise ArgumentError("some help message")
这个构造函数调用有点不方便,所以有一些易于使用的智能构造函数:
def leaf(value):
return BinTree(value=value)
def branch(left, right):
return BinTree(left=left, right=right)
我们如何获得价值? 让我们为此做一些帮助:
def left(tree):
if tree.isLeaf:
raise ArgumentError ("tree is leaf")
else:
return tree.value[0]
def right(tree):
if tree.isLeaf:
raise ArgumentError ("tree is leaf")
else:
return tree.value[1]
def value(tree):
if not tree.isLeaf:
raise ArgumentError ("tree is branch")
else:
return tree.value
而已。 你有一个纯粹的“代数”数据类型,可以通过函数访问:
def count(bin_tree):
if bin_tree.isLeaf:
return 1
else:
return count(left(bin_tree))+count(right(bin_tree))
最接近的可能是带方法的类:
class Leaf:
def __init__(self, value):
self.value = value
def height(self):
return 1
def count(self):
return 1
class Branch:
def __init__(self, left, right):
self.left = left
self.right = right
def height(self):
return 1 + max(self.left.height(), self.right.height())
def count(self):
return 1 + self.left.count() + self.right.count()
虽然这有些惯用并且有其自身的优势,但它也缺乏Haskell版本的一些特性。 最重要的是,函数定义必须与类一起在同一模块中定义。 您可以使用单调度泛型函数而不是方法来获取它。 结果比方法和Haskell函数更开放世界,并且允许在有益的情况下将定义分布在多个模块上。
@singledispatch
def height(_):
raise NotImplementedError()
@singledispatch
def count(_):
raise NotImplementedError()
class Leaf:
def __init__(self, value):
self.value = value
@height.register(Leaf)
def height_leaf(leaf):
return 1
@height.register(Leaf)
def count_leaf(leaf):
return 1
class Branch:
def __init__(self, left, right):
self.left = left
self.right = right
@height.register(Branch)
def height_branch(b):
return 1 + max(b.left.height(), b.right.height())
@count.register(Branch)
def count_branch(b):
return 1 + b.left.count() + b.right.count()
Python没有像Haskell那样的“数据构造函数”的概念。 您可以像大多数其他OOP语言一样创建类。 或者,您始终可以使用内置函数表示数据类型,并且只定义处理它们的函数(这是用于在heapq
内置模块中实现堆的方法)。
python和haskell之间的区别很大,所以最好避免在haskell和python的语法/特性之间进行严格的比较,否则你最终会编写非pythonic和低效的python代码。
即使python确实具有某些功能特性,它也不是一种功能语言,因此您必须完全改变程序的范例,以获得可读,pythonic和高效的程序。
使用类的可能实现可以是:
class Bint(object):
def __init__(self, value, left=None, right=None):
self.a = value
self.left = left
self.right = right
def height(self):
left_height = self.left.height() if self.left else 0
right_height = self.right.height() if self.right else 0
return 1 + max(left_height, right_height)
def count(self):
left_count = self.left.count() if self.left else 0
right_height = self.right.count() if self.right else 0
return 1 + left_count + right_count
该代码可以被简化有点提供一个“聪明”的默认值, left
和right
:
class Nil(object):
def height(self):
return 0
count = height
nil = Nil()
class Bint(object):
def __init__(self, value, left=nil, right=nil):
self.value = value
self.left = left
self.right = right
def height(self):
return 1 + max(self.left.height(), self.right.height())
def count(self):
return 1 + self.left.count() + self.right.count()
请注意,这些实现允许只有一个子节点的节点。
然而,你不必使用类定义的数据类型。 例如,您可以说Bint
可以是单个元素的列表,根的值,也可以是包含三个元素的列表:值,左子项和右子项。
在这种情况下,您可以将函数定义为:
def height(bint):
if len(bint) == 1:
return 1
return 1 + max(height(bint[1]), height(bint[2]))
def count(bint):
if len(bint) == 1:
return 1 + count(bint[1]) + count(bint[2])
另一种方法是使用namedtuple
:
from collections import namedtuple
Leaf = namedtuple('Leaf', 'value')
Branch = namedtuple('Branch', 'value left right')
def height(bint):
if len(bint) == 1: # or isinstance(bint, Leaf)
return 1
return 1 + max(height(bint.left), height(bint.right))
def count(bint):
if len(bint) == 1: # or isinstance(bint, Leaf)
return 1 + count(bint.left) + count(bint.right)
自上次更新以来的五年,但这是我的答案。
使data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving (Show)
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving (Show)
到python ...
class Tree:
def __init__(self):
pass
def height(self):
pass
def count(self):
pass
class Leaf(Tree):
def __init__(self, value):
self.value = value
def __str__(self):
return("Leaf " + str(self.value))
def height(self):
return 1
def count(self):
return 1
class Branch(Tree):
def __init__(self, left, right):
if isinstance(left, Tree) and isinstance(right, Tree):
self.left = left
self.right = right
else:
raise ValueError
def __str__(self):
return("Branch (" + str(self.left) + " " +
str(self.right) + ")")
def height(self):
return 1 + max(self.left.height(), self.right.height())
def count(self):
return 1 + self.left.count() + self.right.count()
#usage : Branch(Leaf(5), Branch(Leaf(3), Leaf(2)))
height
, count
方法 class Tree:
def __init__(self, tree, type_):
def typecheck(subtree):
if isinstance(subtree, Leaf):
if not isinstance(subtree.value, type_):
print(subtree.value)
raise ValueError
elif isinstance(subtree, Branch):
typecheck(subtree.left)
typecheck(subtree.right)
else:
raise ValueError
typecheck(tree)
self.tree = tree
self.type_ = type_
def __str__(self):
return ("Tree " + self.type_.__name__ + "\n" + str(self.tree))
def height(self):
if isinstance(self, Leaf):
return 1
elif isinstance(self, Branch):
return 1 + max(self.left.height(), self.right.height())
else:
return self.tree.height()
def count(self):
if isinstance(self, Leaf):
return 1
elif isinstance(self, Branch):
return 1 + self.left.count() + self.right.count()
else:
return self.tree.count()
class Leaf(Tree):
def __init__(self, value):
self.value = value
def __str__(self):
return("Leaf " + str(self.value))
class Branch(Tree):
def __init__(self, left, right):
if isinstance(left, Tree) and isinstance(right, Tree):
self.left = left
self.right = right
else:
raise ValueError
def __str__(self):
return("Branch (" + str(self.left) + " " +
str(self.right) + ")")
#usage tree1 = Tree(Branch(Leaf(5), Branch(Leaf(3), Leaf(2))), int)
#usage tree1.height() -> 3
#usage tree1.count() -> 5
height
, count
方法 class Tree:
def __init__(self, tree, type_):
def typecheck(subtree):
if isinstance(subtree, Leaf):
if not isinstance(subtree.value, type_):
print(subtree.value)
raise ValueError
elif isinstance(subtree, Branch):
typecheck(subtree.left)
typecheck(subtree.right)
else:
raise ValueError
typecheck(tree)
self.tree = tree
self.type_ = type_
def __str__(self):
return ("Tree " + self.type_.__name__ + "\n" + str(self.tree))
def height(self):
return self.tree.height()
def count(self):
return self.tree.count()
class Leaf(Tree):
def __init__(self, value):
self.value = value
def __str__(self):
return("Leaf " + str(self.value))
def height(self):
return 1
def count(self):
return 1
class Branch(Tree):
def __init__(self, left, right):
if isinstance(left, Tree) and isinstance(right, Tree):
self.left = left
self.right = right
else:
raise ValueError
def __str__(self):
return("Branch (" + str(self.left) + " " +
str(self.right) + ")")
def height(self):
return 1 + max(self.left.height(), self.right.height())
def count(self):
return 1 + self.left.count() + self.right.count()
#usage Tree(Branch(Leaf(5), Branch(Leaf(3), Leaf(2))), int)
#usage tree1.height() -> 3
#usage tree1.count() -> 5
height
, count
方法以外的类(最喜欢的Haskell) class Tree:
def __init__(self, tree, type_):
def typecheck(subtree):
if isinstance(subtree, Leaf):
if not isinstance(subtree.value, type_):
print(subtree.value)
raise ValueError
elif isinstance(subtree, Branch):
typecheck(subtree.left)
typecheck(subtree.right)
else:
raise ValueError
typecheck(tree)
self.tree = tree
self.type_ = type_
def __str__(self):
return ("Tree " + self.type_.__name__ + "\n" + str(self.tree))
class Leaf(Tree):
def __init__(self, value):
self.value = value
def __str__(self):
return("Leaf " + str(self.value))
class Branch(Tree):
def __init__(self, left, right):
if isinstance(left, Tree) and isinstance(right, Tree):
self.left = left
self.right = right
else:
raise ValueError
def __str__(self):
return("Branch (" + str(self.left) + " " +
str(self.right) + ")")
def height(tree):
if not isinstance(tree, Tree):
raise ValueError
if isinstance(tree, Leaf):
return 1
elif isinstance(tree, Branch):
return 1 + max(height(tree.left), height(tree.right))
else:
return height(tree.tree)
def count(tree):
if not isinstance(tree, Tree):
raise ValueError
if isinstance(tree, Leaf):
return 1
elif isinstance(tree, Branch):
return 1 + count(tree.left) + count(tree.right)
else:
return count(tree.tree)
#usage tree1 = Tree(Branch(Leaf(5), Branch(Leaf(3), Leaf(2))), int)
#usage height(tree1) -> 3
#usage count(tree1) -> 5
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.