我假装创建一个高阶函数,该功能用作其参数之一,属于某个数据类型的记录。
例如:
type Debt = Float
type Power = Int
Data State = S String Debt
Data City = C String Power Debt
Data Country = Country
{ states :: [State]
, cities :: [City] }
upDetail :: (Country -> [a])
-> ([a] -> b -> [a])
-> b -> Country -> Country
upDetail f g b country = country { f = new }
where old = f country
new = g old b
上面的功能应该做的是选择国家记录的元素(具有函数类型Country -> [a]
),并根据某个功能类型[a] -> b -> [a]
和某个b
但是,当我尝试编译时,我会发现一个错误说:
" f"不是(可见的)构造函数字段名称
有什么办法可以克服这个问题?我想到使用也许是我的结果,但我不知道该怎么做。
正如评论所述,对此的正常解决方案是使用镜头:
upDetail :: Lens Country [a]
-> ([a] -> b -> [a])
-> b -> Country -> Country
upDetail f g b country = set f country new
where old = get f country
new = g old b
但是,镜头并不难处理,尤其是为了简单的目的。
表达镜头的最简单方法是作为getter和setter函数:
data Lens s a = Lens
{ get :: s -> a
, set :: s -> a -> s
}
_states :: Lens Country [State]
_states = Lens states $ c new -> c { states = new }
_cities :: Lens Country [City]
_cities = Lens cities $ c new -> c { cities = new }
这使我们可以轻松地修改一个国家的城市或状态:
λ Country [] []
Country {states = [], cities = []}
λ upDetail _cities (cs c -> c:cs) (C "Hereford" 100 3000) it
Country {states = [], cities = [C "Hereford" 100 3000.0]}
λ upDetail _states (cs c -> c:cs) (S "Delmarva" 4) it
Country {states = [S "Delmarva" 4.0], cities = [C "Hereford" 100 3000.0]}
一旦您开始考虑编写镜头,镜头就会变得更加复杂,但您可以进入这里,但您可以。