我收集了大约十几种我定义的类型的结构化东西(比如说Component
),其中每个都可以用“名称”来标识,而且努力理清一个惯用的Haskell实例化和检索方法。这些东西在我的应用程序中经常使用,因此概念上它们是一组全局常量或常量表,理想情况下这些常量将被初始化并保存以供快速检索。Haskell成语,用于设置索引结构化值的集合
我目前的做法,我不舒服,只是使用一个函数来从它的名字“计算”每个Component
。
data Component = Component {
someData :: !String,
otherData :: ![Int]
} deriving Show
component :: Name -> Component
component n = case n of
-- about a dozen in the application
"1" -> Component "lasdkfj;alksdjfalkf" [1]
"Q" -> Component "nvjufhhqwe" [5,10,11]
"other" -> Component "ugugugu" []
"A" -> Component "alkkjsfkjaleifuhqiweufjc" []
"B" -> Component "randomletters" []
"C" -> Component "nothingimportant" [9,10]
"b" -> Component "uk" []
"c" -> Component "x" [4,2,7,9,0]
"" -> Component "ABC" []
-- if not listed above, the Component is computed
otherwise -> Component (someFunctionOf n) (someOtherFunctionOf n)
这不适合我。首先,Component
的名称实际上是Component
的一部分,但不包含在该类型中。更重要的是,甚至可以计算常量值,但实际上它们只能在某个表中初始化。
考虑到这一点我也试过
type Name = String
import Data.Maybe
import Data.Map
data Component = Component {
name :: Name,
someDate :: String,
otherData :: [Int]
} deriving Show
components = fromList $ (\c -> (name c, c)) <$> [
Component "1" "lasdkfj;alksdjfalkf" [1],
Component "Q" "nvjufhhqwe" [5,10,11],
Component "other" "ugugugu" [],
Component "A" "alkkjsfkjaleifuhqiweufjc" [],
Component "B" "randomletters" [],
Component "C" "nothingimportant" [9,10],
Component "b" "uk" [],
Component "c" "x" [4,2,7,9,0],
Component "" "ABC" []
]
component :: Name -> Component
component n | isNothing c = Component n (someFunctionOf n) (someOtherFunctionOf n)
| otherwise = fromJust c
where c = Data.Map.lookup n components
这显然已经处理了“常量”值作为常量的优势,但觉得尴尬,因为它引入了一个中间值(Map
components
)并在那里复制名称(在Component
中并作为相应的键)。
无论如何,我觉得我正在解决这一切都是错误的,并且必须有更好的方法来建立一组索引结构化值,其中包括一堆常量和计算值。
优秀!你可以多说一点关于第二次导入的注释('import Data.Map(Map)')。另外我想我需要'M.fromList'。是我的lambda生成'组件'好吗?我确实“控制”了这一点,所以“名称”的重复不是这样的问题(正如您正确指出的那样)。是否有Haskell成语来命名这种“私人”或“内部”值? – orome
@raxacoricofallapatorius(1)'import Data.Map(Map)'只是为了让类型签名少一点噪音。离开它是完全可以的;它只意味着你必须编写'components :: M.Map Name Component'。 (2)'M.fromList'的确如此。 (3)拉姆达很好。有一些无点的写法,例如'liftA2(,)name id'('liftA2'在'Control.Applicative'中)和'name &&& id'('(&&&)'在'Control.Arrow '),但在这种情况下,选择很大程度上是品味的问题(有些人会认为免费版本更清晰,而其他人会觉得它们混淆)。 – duplode
@raxacoricofallapatorius(4)“是否有Haskell成语命名这样的”私有“或”内部“值? - 不是真的;只要将它们命名为其他名称即可。这也意味着即使对于内部价值也要有合理清晰的名称,以便人们更容易阅读您的实施。此外,对于具有局部作用域的函数(函数参数,where子句定义等),使用较短和较少的描述性名称通常是可以的,因为在大多数情况下,有可能在快速浏览。 – duplode