Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何将重载记录字段与镜头一起使用?_Haskell_Typeclass_Haskell Lens - Fatal编程技术网

Haskell 如何将重载记录字段与镜头一起使用?

Haskell 如何将重载记录字段与镜头一起使用?,haskell,typeclass,haskell-lens,Haskell,Typeclass,Haskell Lens,在某种程度上,可以将类与镜头混合以模拟过载的记录字段。例如,请参见中的makeFields。我试图找出是否有一种好的方法,在某些类型中重复使用相同的名称作为镜头,在其他类型中重复使用相同的名称作为遍历。值得注意的是,给定一个乘积和,每个乘积都可以有透镜,这将退化为该和的遍历。我能想到的最简单的事情是: 初试 这适用于简单的事情,比如 data Boop = Boop Int Char instance Boo Boop where type Con Boop = Functor boo

在某种程度上,可以将类与镜头混合以模拟过载的记录字段。例如,请参见中的
makeFields
。我试图找出是否有一种好的方法,在某些类型中重复使用相同的名称作为镜头,在其他类型中重复使用相同的名称作为遍历。值得注意的是,给定一个乘积和,每个乘积都可以有透镜,这将退化为该和的遍历。我能想到的最简单的事情是:

初试 这适用于简单的事情,比如

data Boop = Boop Int Char
instance Boo Boop where
  type Con Boop = Functor
  boo f (Boop i c) = (\i' -> Boop i' c) <$> f i
它应该能够产生
遍历
,而不管选择底层
Boo

第二次尝试 我尝试的下一件事是约束
Con
族,这是可行的。这有点恶心。首先,改变类别:

class LTEApplicative c where
  lteApplicative :: Applicative a :- c a

class LTEApplicative (Con booey) => Boo booey where
  type Con booey :: (* -> *) -> Constraint
  boo :: forall f . Con booey f => (Int -> f Int) -> booey -> f booey
这使得
Boo
实例携带明确的证据,证明它们的
Boo
产生了
遍历'booey Int
。还有一些东西:

instance LTEApplicative Applicative where
  lteApplicative = Sub Dict

instance LTEApplicative Functor where
  lteApplicative = Sub Dict

-- flub :: Boo booey => Traversal booey booey Int Int
flub :: forall booey f . (Boo booey, Applicative f) => (Int -> f Int) -> booey -> f booey
flub = case lteApplicative of
         Sub (Dict :: Dict (Con booey f)) -> boo

instance Boo boopy => Boo (Maybe boopy) where
  type Con (Maybe boopy) = Applicative
  boo _ Nothing = pure Nothing
  boo f (Just x) = Just <$> hum f x
    where hum :: Traversal' boopy Int
          hum = flub

以下内容以前对我有用:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

import Control.Lens

data Boop = Boop Int Char deriving (Show)

class HasBoo f s where
  boo :: LensLike' f s Int

instance Functor f => HasBoo f Boop where
  boo f (Boop a b) = flip Boop b <$> f a

instance (Applicative f, HasBoo f s) => HasBoo f (Maybe s) where
  boo = traverse . boo
也可以有点疯狂,将单个类用于所有“has”功能:

{-# LANGUAGE
  UndecidableInstances, MultiParamTypeClasses,
  RankNTypes, TypeFamilies, DataKinds,
  FlexibleInstances, FunctionalDependencies,
  TemplateHaskell #-}

import Control.Lens hiding (has)
import GHC.TypeLits
import Data.Proxy

class Has (sym :: Symbol) f s t a b | s sym -> a, sym t -> b, s b -> t, t a -> s where
  has' :: Proxy sym -> LensLike f s t a b

data Foo a = Foo {_fooFieldA :: a, _fooFieldB :: Int} deriving Show
makeLenses ''Foo

instance Functor f => Has "fieldA" f (Foo a) (Foo a') a a' where
  has' _ = fooFieldA
使用GHC 8,可以添加

{-# LANGUAGE TypeApplications #-}
并避免使用代理:

has :: forall (sym :: Symbol) f s t a b. Has sym f s t a b => LensLike f s t a b
has = has' (Proxy :: Proxy sym)

instance (Applicative f, Has "fieldA" f s t a b) => Has "fieldA" f (Maybe s) (Maybe t) a b where
  has' _ = traverse . has @"fieldA"
示例:

> Just (Foo 0 1) ^? has @"fieldA"
Just 0
> Foo 0 1 & has @"fieldA" +~ 10
Foo {_fooFieldA = 10, _fooFieldB = 1}

真的这么不方便吗
flub
可以一劳永逸地编写,因此只需将其命名为
boo
,并将
boo
重命名为
booWithCon
。用户永远不必知道
booWithCon
或任何底层机器。对于一个实现者来说,与实例1相比,它需要一个额外的行——确切地说,你会考虑什么不方便?@ USER 2407038,我的目标是,名称<代码> BOO可以用作<代码>镜片< /C> >(在可用的地方),或者仅是<代码>遍历< /代码>(否则)。code>flub只是一个
遍历
;它从来不是一个
镜头
。非常好。我还在研究它,但它似乎提供了一个比我想到的更好的界面。
{-# LANGUAGE
  UndecidableInstances, MultiParamTypeClasses,
  RankNTypes, TypeFamilies, DataKinds,
  FlexibleInstances, FunctionalDependencies,
  TemplateHaskell #-}

import Control.Lens hiding (has)
import GHC.TypeLits
import Data.Proxy

class Has (sym :: Symbol) f s t a b | s sym -> a, sym t -> b, s b -> t, t a -> s where
  has' :: Proxy sym -> LensLike f s t a b

data Foo a = Foo {_fooFieldA :: a, _fooFieldB :: Int} deriving Show
makeLenses ''Foo

instance Functor f => Has "fieldA" f (Foo a) (Foo a') a a' where
  has' _ = fooFieldA
{-# LANGUAGE TypeApplications #-}
has :: forall (sym :: Symbol) f s t a b. Has sym f s t a b => LensLike f s t a b
has = has' (Proxy :: Proxy sym)

instance (Applicative f, Has "fieldA" f s t a b) => Has "fieldA" f (Maybe s) (Maybe t) a b where
  has' _ = traverse . has @"fieldA"
> Just (Foo 0 1) ^? has @"fieldA"
Just 0
> Foo 0 1 & has @"fieldA" +~ 10
Foo {_fooFieldA = 10, _fooFieldB = 1}