我正在尝试为多种类型创建一个多态镜头decleration(没有模板haskell)。
module Sample where
import Control.Lens
data A = A {_value:: Int}
data B = B {_value:: Int}
data C = C {_value:: String}
value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
但我得到以下错误:
Ambiguous occurrence ‘_value’
It could refer to either the field ‘_value’,
defined at library/Sample.hs:5:13
or the field ‘_value’, defined at
library/Sample.hs:4:13
or the field ‘_value’, defined at
library/Sample.hs:3:13
|
6 | value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
| ^^^^^^
所以,目标是让value
镜头适用于所有三种类型A,B和C.有没有办法实现这一目标?
感谢。
答案 0 :(得分:7)
generic-lens可以在没有TH的情况下导出镜头。您可以将通用field
镜头专门化为特定字段,并为其命名如下。
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
import GHC.Generics (Generic)
import Control.Lens (Lens, (^.))
import Data.Generics.Product (HasField(field))
data A = A { _value :: Int } deriving Generic
data B = B { _value :: Int } deriving Generic
data C = C { _value :: String } deriving Generic
value :: HasField "_value" s t a b => Lens s t a b
value = field @"_value"
main :: IO ()
main = print (A 0 ^. value, B 0 ^. value, C "0" ^. value)
答案 1 :(得分:4)
Haskell不像Java或C ++这样的语言支持重载函数。要做你想做的事,你需要使用类似的类型类。
class HasValue a b where
value :: Lens' a b
data A = A {_valueA:: Int}
data B = B {_valueB:: Int}
data C = C {_valueC:: String}
instance HasValue A Int where
value = lens _valueA (\i x -> i{_valueA=x})
instance HasValue B Int where
value = lens _valueB (\i x -> i{_valueB=x})
instance HasValue C String where
value = lens _valueC (\i x -> i{_valueC=x}
您需要启用多参数类型类来执行此操作。
答案 2 :(得分:0)
如果你想避免DuplicateRecordFields
,另一种选择是在自己的模块中定义所有内容,尽管这需要将合格的导入导入到同一个模块中。
module Sample.A where
import Control.Lens
data A = A {_value:: Int}
value = lens _value (\i x -> i{_value=x})
module Sample.B where
import Control.Lens
data B = B {_value:: Int}
value = lens _value (\i x -> i{_value=x})
module Sample.C where
import Control.Lens
data C = C {_value:: String}
value = lens _value (\i x -> i{_value=x})
module Main where
import qualified Sample.A as A
import qualified Sample.B as B
import qualified Sample.C as C
main :: IO ()
main = print (A.A 0 ^. A.value, B.B 0 ^. B.value, C.C "0" ^. C.value)