如何在 Haskell 中比较镜头

Posted

技术标签:

【中文标题】如何在 Haskell 中比较镜头【英文标题】:How to compare lenses in Haskell 【发布时间】:2022-01-04 17:39:28 【问题描述】:

我对镜头的 Eq 实例很好奇。 镜头是功能。很难比较任意函数,但镜头是一类特殊的函数。

我正在考虑为s 类型使用 QuickCheck 任意实例:

lensesAreEqual :: 
  (Arbitrary a, Eq a) => 
  Lens' s a -> 
  Lens' s a -> 
  Gen Bool
lensesAreEqual l1 l2 = 
  and <$> forM [0..100] $ \_ -> do
    s <- arbitrary
    pure $ s ^. l1 == s ^.l2

我可以将 lensAreEqual monad 放在 unsafePerformIO 后面以获得整洁的 Eq 实例。

有人知道更好的解决方案吗?

【问题讨论】:

您可以轻松地为任何功能执行此操作。它可能在务实的意义上起作用,以确定 2 个函数是否“似乎相等”。但是我非常不愿意在带有 UnsafePerformIO 的纯代码中使用它。至少从理论上讲,这可以告诉您相同的 2 个函数在某些运行中相等,但在其他运行中不相等! 一般来说,没有合适的方法来做到这一点。你为什么还要这样做? @JosephSible-ReinstateMonica 我想概括 shim 以在基于砖的应用程序中滚动多个列表小部件,并在 Name 中携带镜头以从事件处理程序中的应用程序状态中选择特定列表。名称应该有 Ord 实例。 由于镜头只是功能,如果您将存储的东西去功能化怎么办? 【参考方案1】:

不要这样做。相反,使用通常的Equality 定义一个真实的数据类型,以及一个解释函数:

data ItemType = Weapons | Armor | Potions deriving (Eq, Ord, Read, Show)

data AppState a = AppState
     _weapons :: [a]
    , _armor :: [a]
    , _potions :: [a]
    , _activeType :: ItemType
     deriving (Eq, Ord, Read, Show)

toLens :: ItemType -> Lens (AppState a) (AppState b) [a] [b]
toLens Weapons = weapons
toLens Armor = armor
toLens Potions = potions

(这就是 cmets 中关于“去功能化”的意思。)

【讨论】:

以上是关于如何在 Haskell 中比较镜头的主要内容,如果未能解决你的问题,请参考以下文章

尼康D型镜头手动对焦应该如何操作?

尼康D型镜头手动对焦应该如何操作?

在 Haskell 中构建组合自参照透镜

Haskell 光学库——Optics

Haskell如何强制在haskell中评估Data.Map?

在 Haskell 中推导是如何工作的?