我对Haskell相当陌生,我一直在努力用记录来编写可读的代码。
我的具体问题是:
someFunction(foo.bar, 2 * foo.bar.baz)
在像Java或C++这样的语言中很容易读懂。在Haskell,我发现自己写这个是为了完成同样的事情。
someFunction (fooBar foo) (2 * barBaz (fooBar foo))
这很难直观地解析,调用多个参数的函数很快就变得不可读了。为了使它更具可读性,我发现自己定义了中间值,它将从记录中提取字段,这更具有可读性,但增加了更多的代码行,因此以另一种方式损害了可读性。是否有更好的方法来使用更具可读性的记录,或者我应该做些什么呢?只是用元组?用大量的参数写入函数,而不是将相关的值分组到记录中?还有别的吗?
发布于 2018-11-16 20:09:23
解决这个问题的一个办法(如注释中所建议的)是使用镜片。使用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库有更好的错误消息,但我没有使用它),特别是当您开始盲目地使用事物时。我建议坚持基本原则(如链接教程中所示) --这将涵盖大部分用例。
https://stackoverflow.com/questions/53328448
复制相似问题