【发布时间】:2019-11-29 10:27:34
【问题描述】:
鉴于这段代码:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FunctionalDependencies #-}
module Foo where
import Control.Lens ((^.), makeFieldsNoPrefix)
import Prelude hiding (id)
data Bar
= Bar1 { _id :: Int
, _name :: String
}
| Bar2 { _name :: String }
$(makeFieldsNoPrefix ''Bar)
data Foo = Foo { _id :: Int
, _name :: String
}
$(makeFieldsNoPrefix ''Foo)
a = (undefined :: Foo) ^. name -- compiles fine
b = (undefined :: Foo) ^. id -- doesnt compile
{-
• No instance for (Monoid Int) arising from a use of ‘id’
• In the second argument of ‘(^.)’, namely ‘id’
In the expression: (undefined :: Foo) ^. id
In an equation for ‘b’: b = (undefined :: Foo) ^. id
-}
据我所知,id 似乎需要一个 Monoid 实例,因为当实例类型为 Bar2(没有 id 字段)时,Bar 可能会失败。
但由于我正在处理 Foo(它总是有一个 id 字段)它应该可以工作,不是吗?
我知道我可以通过在字段前面加上类名来解决这个问题,例如:
data Foo = Foo { _fooId :: Int, _fooName :: String }
但如果有一个不错的解决方案而不会使我的字段名称混乱,那么我全力以赴:-)
【问题讨论】:
-
呃,我认为这里至少有三件事通常是个坏主意:1. 为 sum 类型创建记录字段。 (镜头确实在一定程度上解决了随之而来的问题,但正如您所遇到的,这也带来了自己的问题。) 2. 重复记录字段。 (始终是一个半生不熟的概念;只有
OverloadedLabels理解了这一点。)3. 不要为不同的东西重复使用标准名称,尤其是对于像@ 这样基本的东西987654330@. -
是的,我知道 1 和 2,但我认为镜头会解决他们的问题 :-(
-
当与 lens 一起使用时,确定 1 是个坏主意吗?在我看来,hackage.haskell.org/package/lens-4.18.1/docs/Control-Lens.html 上的第一个例子是使用 sum 类型的记录,如果这是一种不好的做法
-
好吧,我认为这是个坏主意。意见可能会有所不同。
-
您可以通过generic-lens 解决很多此类问题。作为奖励,没有 TH 拼接!
标签: haskell haskell-lens monoids