按值修改Haskell嵌套记录

时间:2017-02-28 18:21:17

标签: haskell records template-haskell lenses

假设我有一个嵌套结构,如下所示:

data Bar = Bar { _id :: Integer, _bars :: [Bar] }
data Foo = Foo { _bars :: [Bar] }

我有Foo一堆Barsid个:

foo = Foo [Bar 1 [Bar 2], Bar 3 [Bar 4, Bar 5]]

如何,或许使用镜头,我修改foo使Bar 5成为Bar 6

我知道我使用fclabels来做这样的事情:

mkLabel ''Foo
mkLabel ''Bar
modify bars (\bars -> ...) foo

但是栏可以无限嵌套。如何找到并修改具有指定ID的Bar

1 个答案:

答案 0 :(得分:4)

是的,@property (nonatomic, retain) UITextField *activeTextField; -(void)setActiveTextField:(UITextField *)activeTextField { _activeTextField = activeTextField; } -(void)textFieldDidBeginEditing:(UITextField *)textField { self.activeTextField = textField; } -(void)textFieldDidEndEditing:(UITextField *)textField { self.activeTextField = nil; } -(void)keyboardWasShown:(NSNotification *)aNotification { if (self.activeTextField == nil) { return; } 可以做到这一点。 Control.Lens.Plated模块包含用于" Scrap Your Boilerplate" -style编程的工具,具有与lens类似的自相似结构。这个想法很诱人:你解释了如何找到节点的直接子节点(通过编写Bar),并且库递归地将遍历应用于整个结构。

Traversal' a a

(如果您不想自己实施{-# LANGUAGE TemplateHaskell #-} import Control.Lens data Bar = Bar { _lbl :: Int, _bars :: [Bar] } deriving (Show) makeLenses ''Bar instance Plated Bar where plate = bars.traverse ,可以导出Data并将plate留空。)

transform :: Plated a => (a -> a) -> a -> a采用修改单个节点并将其应用于整个结构的函数。

instance

使用您问题中的示例:

fiveToSix :: Bar -> Bar
fiveToSix = transform go
    where go bar
            | bar^.lbl == 5 = bar & lbl .~ 6
            | otherwise = bar

另一个例子是,对于funzies,让我们使用cosmosghci> let bars = [Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 5 []]] ghci> map fiveToSix bars [Bar 1 [Bar 2 []], Bar 3 [Bar 4 [], Bar 6 []]] 中提取所有Bar 5

Bar