定义一个可以访问数据记录的高阶函数

时间:2017-12-07 18:53:28

标签: haskell

我假装创建一个高阶函数,该函数使用属于某个数据类型记录的函数作为其参数之一。

例如:

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'不是(可见)构造函数字段名称

有什么办法可以解决这个问题吗?我想过使用可能国家作为我的结果,但我不知道该怎么做。

1 个答案:

答案 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]}

一旦你开始考虑合成镜头,镜头会变得稍微复杂一些,但你可能不会进入镜头,但是你可以这样做。