问题在标题中:)
我的代码:
data tree a = Leaf a | Node (tree a) (tree a)
treeo = Node((Node(Leaf 1)(Node (Leaf 10)(Leaf 11))))
(Node(Leaf 12)(Leaf 13))
-- count all leafs:
lcounter(Leaf a) = 1
lcounter(Node a b)= lcounter a + lcounter b
-- count all nodes?:
答案 0 :(得分:6)
首先注意数据类型定义应该从大写开始:
data Tree a = Leaf a | Node (Tree a) (Tree a)
要统计所有节点,它几乎就是你所做的,一个简单的模式匹配树数据构造函数:
countNodes :: Tree a -> Int
countNodes (Leaf a) = 0
countNodes (Node left right) = 1 + countNodes left + countNodes right
用你的例子:
let tree = Node((Node (Leaf 1) (Node (Leaf 10) (Leaf 11))))(Node (Leaf 12) (Leaf 13))
countNodes tree -- 4
答案 1 :(得分:3)
让机器完成工作。两个计数函数都是一个更通用概念的实例,折叠。我将编写少量代码来折叠树,并使用它来免费定义所需的两个计数函数。
我首先稍微概括一下您的Tree
类型,在b
s内部标记为Node
s,并在a
处外部标记为Leaf
s data Tree a b = Leaf a | Node (Tree a b) b (Tree a b)
秒。
Tree
您的原始Tree a ()
类型相当于Tree
。
此Bifoldable
版本是名为Bifoldable
的有用类的实例。 instance Bifoldable Tree where
bifoldMap f g (Leaf a) = f a
bifoldMap f g (Node l x r) = bifoldMap f g l `mappend` g x `mappend` bifoldMap f g r
通用Foldable
来处理具有两个类型参数的数据类型。
bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> Tree a b -> m
Tree
使用Monoid
将a
折叠为单个值。它会标识树中的所有b
和f
,对其应用g
或m
以获取mappend
,然后使用countLeaves
将结果结构压缩成单个值。
这是我要编写的唯一非常重要的代码。其他一切只是操纵类型; countNodes
和bifoldMap
都会被Bifoldable
的牙膏管挤压。 (有一些Template Haskell helpers可以为您生成Bifoldable
的实例,因此您甚至不需要编写能够完成这项工作的代码!)
每个Foldable
在两个方面自动为Bifoldable
。 The WrappedBifunctor
newtype将Foldable
转换为newtype WrappedBifunctor p a b = WrapBifunctor { unwrapBifunctor :: p a b }
instance Bifoldable p => Foldable (WrappedBifunctor p a) where
foldMap f = bifoldMap (const mempty) f . unwrapBifunctor
聚合其第二个参数。
b
这已足以为我们提供一种计算节点的方法。计算节点与计算length
类型参数的出现次数相同,这正是Foldable
对任何Foldable
所做的事情。我们所要做的就是将树包裹起来以获得-- i lied, this is nontrivial too - but it's already in the standard library
length :: Foldable t => t a -> Int
length = foldl' (\c _ -> c+1) 0
countNodes :: Tree a b -> Int
countNodes = length . WrapBifunctor
ghci> let myTree = Node (Node (Leaf 'a') () (Leaf 'b')) () (Node (Leaf 'c') () (Leaf 'd'))
ghci> countNodes myTree
3
。
a
如何计算叶子?这次我们需要计算WrappedBifunctor
类型参数的出现次数。 Tree
也可以在这里提供帮助:我们可以重新排列a
的参数,以便Foldable
是第二个参数,然后将其包装起来 - 生成的a
实例将计算b
而不是flip
s。为此,我们需要the Flip
newtype,它会切换参数的参数,就像newtype Flip p a b = Flip { runFlip :: p b a }
instance Bifoldable p => Bifoldable (Flip p) where
bifoldMap f g = bifoldMap g f . runFlip
在值级别那样:
countLeaves :: Tree a b -> Int
countLeaves = length . WrapBifunctor . Flip
ghci> countLeaves myTree
4
现在我们可以免费计算叶子了:
Bifoldable
最后,您可以使用bilength :: Bifoldable t => t a b -> Int
bilength = bifoldl' (\c _ -> c+1) (\c _ -> c+1) 0
countLeavesAndNodes :: Tree a b -> Int
countLeavesAndNodes = bilength
-- equivalent to, but more efficient than...
-- countLeavesAndNodes t = countLeaves t + countNodes t
类中的bilength
函数计算叶和节点。
Flip
Haskell的理念是一劳永逸地解决这样的问题,并将这些一般解决方案应用于特定案例。像WrappedBifunctor
和Bifunctor
这样的新类型让我们表达了一般属性(例如"每个Bifunctor
仍然是a
之后你翻转它的参数")没有运行时成本。我们使用这些属性来操作类型类系统,编写代码来为我们计算b
和Bifoldable
。
当你继续学习Haskell时,当程序是一般模式的一个实例时,你会发现它。设置上面的NSArray *sectionArray;
int sectionCount=0;
NSDictionary *orderedData;
NSString *checkInStr, *checkOutStr;
NSString *govtTaxes, *enhancementTotal, *grandTotal;
- (void)viewDidLoad {
[super viewDidLoad];
[self setupTable];
[self.bookingsTableView reloadData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewDidDisappear:(BOOL)animated {
if(doesSendNotification){
NSLog(@"summary view disappeared");
[[NSNotificationCenter defaultCenter] postNotificationName:@"SummaryViewDismissedNotification" object:self];
}
}
-(void)viewWillAppear:(BOOL)animated {
[self.bookingsTableView reloadData];
}
-(void)setupTable {
self.bookingsTableView.rowHeight = UITableViewAutomaticDimension;
self.bookingsTableView.estimatedRowHeight = 50.0;
sectionArray = [[SummaryModel sharedInstance] getTableSections:self.s_sendEnhancementServerDict];
orderedData = [[SummaryModel sharedInstance] getOrderedData:self.s_sendEnhancementServerDict];
[self.bookingsTableView reloadData];
}
#pragma mark- UITableview delegate and datasource methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if(section==0){
return 3;
} else if (section>0 && section<(sectionCount-1)){
int rows=(int)[[orderedData objectForKey:(NSString*)[sectionArray objectAtIndex:section]] count];
return rows;
} else {
return 4;
}
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return (NSString*)[sectionArray objectAtIndex:section];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier;
UITableViewCell *cell;
// UITableView *table = (UITableView*)[self.view viewWithTag:11];
if (indexPath.section==0 && indexPath.row>=0 && indexPath.row<=2) {
cellIdentifier =@"SplitCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *l1 = (UILabel*)[cell viewWithTag:1];
UILabel *l2 = (UILabel*)[cell viewWithTag:2];
if(indexPath.row==0){
l1.attributedText = [self getStyledString1:@"Hotel Name"];
l2.attributedText = [self getStyledString:self.s_propertyName];
} else if(indexPath.row==1){
l1.attributedText = [self getStyledString1:@"Arrival Date:"];
l2.attributedText = [self getStyledString:checkInStr];
} else if(indexPath.row==2){
l1.attributedText = [self getStyledString1:@"Departure Date:"];
l2.attributedText = [self getStyledString:checkOutStr];
}
} else if (indexPath.section>0 && indexPath.section<(sectionCount-1)) {
// for(int i=0;i<5;i++){
cellIdentifier=@"VerticalLabelCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *l3 = (UILabel*)[cell viewWithTag:3];
UILabel *l4 = (UILabel*)[cell viewWithTag:4];
l3.layer.backgroundColor = GOLDEN_COLOR.CGColor;
NSArray *roomTypeArray = [orderedData objectForKey:(NSString*)[sectionArray objectAtIndex:indexPath.section]];
NSDictionary *roomD = [roomTypeArray objectAtIndex:indexPath.row];
NSString *header = [roomD objectForKey:@"room_type_name"];
NSAttributedString *sH = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" %@",header] attributes:@{NSFontAttributeName:ARIAL_FONT_BOLD}];
l3.attributedText = sH;
int roomCount = [(NSNumber*)[roomD objectForKey:@"room_units"] intValue];
NSMutableAttributedString *labelText = [[NSMutableAttributedString alloc] init];
for(int i=0;i<roomCount;i++){
NSString *roomNo = [NSString stringWithFormat:@"\n Room # %d\n",i+1];
NSAttributedString *s = [[NSAttributedString alloc] initWithString:roomNo attributes:@{NSFontAttributeName:ARIAL_FONT_BOLD, NSUnderlineStyleAttributeName:@(NSUnderlineStyleSingle)}];
[labelText appendAttributedString:s];
NSString *adults = [NSString stringWithFormat:@" Adults: %@ \t\t Max. Adults: %@ \n",[roomD objectForKey:@"max_adults"],[roomD objectForKey:@"max_adults"]];
NSAttributedString *s1 = [[NSAttributedString alloc] initWithString:adults attributes:@{NSFontAttributeName:ARIAL_FONT_BOLD}];
[labelText appendAttributedString:s1];
NSArray *enhanc = [(NSArray*)[roomD objectForKey:@"room_features"] objectAtIndex:i];
for(int i=0;i<[enhanc count];i++){
[labelText appendAttributedString:[self getStyledString2:[NSString stringWithFormat:@" %@\n", [enhanc objectAtIndex:i]]]];
}
l4.attributedText = labelText;
}
} else if(indexPath.section==(sectionCount-1)){
cellIdentifier =@"SplitCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *l1 = (UILabel*)[cell viewWithTag:1];
UILabel *l2 = (UILabel*)[cell viewWithTag:2];
if(indexPath.row==0){
l1.attributedText = [self getStyledString1:@"Room Charges:"];
l2.attributedText = [self getStyledString:[NSString stringWithFormat:@"£ %@", self.s_priceOfRooms]];
}else if(indexPath.row==1){
l1.attributedText = [self getStyledString1:@"Government Taxes:"];
l2.attributedText = [self getStyledString:[NSString stringWithFormat:@"£ %@", govtTaxes]];
}else if(indexPath.row==2){
l1.attributedText = [self getStyledString1:@"Enhancement Total:"];
l2.attributedText = [self getStyledString:[NSString stringWithFormat:@"£ %@", enhancementTotal]];
}else if(indexPath.row==3){
l1.attributedText = [self getStyledString1:@"Total Charges"];
l2.attributedText = [self getStyledString:[NSString stringWithFormat:@"£ %@", grandTotal]];
}
}
return cell;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
sectionCount = (int)[sectionArray count];
return sectionCount;
}
-(void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section {
view.tintColor = GOLDEN_COLOR;
}
-(NSAttributedString*)getStyledString:(NSString*)input {
NSAttributedString *str = [[NSAttributedString alloc] initWithString:input attributes:@{NSForegroundColorAttributeName:GOLDEN_COLOR, NSFontAttributeName:ARIAL_FONT}];
return str;
}
-(NSAttributedString*)getStyledString1:(NSString*)input {
NSAttributedString *str = [[NSAttributedString alloc] initWithString:input attributes:@{NSFontAttributeName:ARIAL_FONT_BOLD}];
return str;
}
-(NSAttributedString*)getStyledString2:(NSString*)input {
NSAttributedString *str = [[NSAttributedString alloc] initWithString:input attributes:@{NSFontAttributeName:ARIAL_FONT}];
return str;
}
实例之类的常规结构很快就会在代码重用中带来好处。