4

给定以下数据类型

data Both a b = Both { left :: a, right :: b }

我可以像这样为 Applicative 等编写实例(在这里省略 Functor,因为我们可以使用DeriveFunctor):

instance Monoid a => Applicative (Both a) where
    pure x = Both mempty x
    Both u f <*> Both v x = Both (u <> v) (f x)

由于Both与 同构(a,b),我想知道是否可以使用DerivingVia来派生实例:

data Both a b = ... deriving Applicative via ((,) a)

这会导致错误消息,例如:

    • Couldn't match representation of type ‘(a, a1)’
                               with that of ‘Both a a1’
        arising from the coercion of the method ‘pure’
          from type ‘forall a1. a1 -> (a, a1)’
            to type ‘forall a1. a1 -> Both a a1’
    • When deriving the instance for (Applicative (Both a))

我将其解释为“编译器不知道如何Both变成(,)”。我如何告诉编译器使用明显的方式来做到这一点?

我已经看到了这个问题和答案,但我希望有一个需要更少样板的解决方案。

4

2 回答 2

4

受到这个答案的启发,并在包的帮助下generic-data可以写:

{-# LANGUAGE DeriveGeneric, DerivingStrategies, DerivingVia #-}

import GHC.Generics
import Generic.Data

data Both a b = Both {left :: a, right :: b}
  deriving stock (Generic1)
  deriving (Functor, Applicative) via Generically1 (Both a)
于 2022-02-21T11:18:48.697 回答
3

DerivingVia论文有一节是关于使用Generic为“同构通过”的事物派生任意类的Generic。见 4.3。

我觉得我已经看到了适用于 hackage 库的方法,但我现在似乎找不到它。

但是,我不确定它是否适用于您的情况,因为(a, b)您的类型可能没有相同的Generic表示形式(您的类型有记录字段)。“数据类型通用手术”在这种情况下也可能有用 - https://github.com/Lysxia/generic-data-surgery#readme

于 2022-02-21T11:48:16.547 回答