给出这段代码:
{-# 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实例,因为Bar在实例为Bar2
类型(它没有id
字段时可能会失败)。
但是由于我正在使用Foo(始终具有id
字段),所以它应该可以工作,不是吗?
我知道我可以通过在字段前面加上类名来解决此问题:
data Foo = Foo { _fooId :: Int, _fooName :: String }
但是如果有一个不错的解决方案而又不会弄乱我的字段名称,那么我全力以赴:-)
因此,这里的问题部分是由sum-type中使用的记录引起的。我们可以为Foo的name
生成一个镜头,因为每个构造函数都有一个name
字段;但是只有一个构造函数具有id
。这将导致TemplateHaskell生成以下HasId
类,您可以通过在ghci中运行:browse Foo
来自己查看: