我假装创建一个高阶函数,该函数使用属于某个数据类型记录的函数作为其参数之一。
例如:
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的记录元素(函数类型为Country -> [a]
)并根据某个函数类型[a] -> b -> [a]
和某个{更改它} {1}}
然而,当我尝试编译这个时,我得到一个错误说:
'f'不是(可见)构造函数字段名称
有什么办法可以解决这个问题吗?我想过使用可能国家作为我的结果,但我不知道该怎么做。
答案 0 :(得分:5)
正如评论所述,正常的解决方法是使用镜头:
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
然而,镜片并不难以处理,特别是对于这么简单的目的。
表达镜头最简单的方法是作为吸气剂和定位器功能:
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]}
一旦你开始考虑合成镜头,镜头会变得稍微复杂一些,但你可能不会进入镜头,但是你可以这样做。