我对Haskell还是很陌生,而我一直在努力的一件事是使用记录编写可读代码。
我的具体问题是:
someFunction(foo.bar, 2 * foo.bar.baz)
someFunction (fooBar foo) (2 * barBaz (fooBar foo))
是否有更好的方法来使用更具可读性的记录,或者我应该做些什么吗?只是使用元组?用大量参数编写函数,而不是将相关值分组到记录中?还有吗?
答案 0 :(得分:2)
解决该问题的一种方法(如注释中所建议)是使用镜片。使用microlens
和microlens-th
包(开始时可能会更简单):
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
import Data.List (nub)
import Lens.Micro ((^.), (^..))
import Lens.Micro.TH (makeFields)
newtype Name = Name String
deriving Eq
data Person = Person { _personName :: Name }
makeFields ''Person
data Species = Dog | Cat
deriving Eq
data Pet = Pet { _petName :: Name, _petSpecies :: Species }
makeFields ''Pet
-- ^. is an infix operator for view
uniquePersonNames :: [Person] -> [Name]
uniquePersonNames ps = nub (map (\p -> p ^. name) ps)
dogs :: [Pet] -> [Pet]
dogs ps = filter (\p -> p ^. species == Dog) ps
data Concert = Concert
{ _concertPerformers :: [Person]
, _concertAttendees :: [Person]
}
makeFields ''Concert
-- ^.. is an infix operator for toListOf
performerNames :: Concert -> [Name]
performerNames c = c ^.. performers . traverse . name
data House = House { _housePeople :: [Person], _housePet :: Pet}
makeFields ''House
houseSound :: House -> String
houseSound h = case h ^. pet . species of
Dog -> "Woof!"
Cat -> "Meow!"
这里有多种资源,可进一步了解透镜和其他种类的光学器件。一种特别适合初学者的资源Control.Lens.Tutorial。
请注意,这种方法会导致难以理解的类型错误(我相信generic-lens
库具有更好的错误消息,但我没有使用过),尤其是如果您盲目使用它们的话。我建议坚持使用基础知识(如链接教程中所述)-这将涵盖您的大部分用例。