这主要是一个风格问题(所以对SO而言可能不是最好的;但我不知道其他任何问题);
在我的问题空间中,我注意到我的许多数据结构代表了Bifunctors;在许多情况下,它们是单一特定类型的Bifunctors。例如:
data Coord = Coord Int Int
data Range = Range Coord Coord
等
我发现使用Bifunctor中的first, second
来映射这些组件的组件非常有用;这当然要求我将它们定义为Bifunctors:
data Coord a b = Coord a b
instance Bifunctor Coord where ...
data Range a b = Range a b
instance Bifunctor Range where ...
我发现了几种类型具有完全相同结构的情况;基本上Pair a = Pair a a
(甚至是元组(a,a),其中数据是一对相同类型的两个元素。为了从Bifunctor(及其所有相关的帮助者和镜头)中受益,我感到很遗憾)我现在需要将Range Coord Coord
指定为我的所有类型;因此我开始使用类型别名type Range = Pair Coord Coord
和type Coord = Pair Int Int
;这使我不会有一堆冗余定义;但是当模式匹配每个案例现在是非描述性的f (Pair a b) = ...
时,我不知道里面是什么。
我通过阅读this informative answer了解到类型本身不应该对它们包含的内容施加限制;所以我想我可以使用像data Range a b = Range a b
,
我想我的问题归结为;是否有一种既定的方法来处理类似数据结构的重复数据删除,同时仍保持良好类型名称/别名的表现力?
现在我有:
data Range a b = Range a b
type CrdRange = Range Coord Coord
但我不喜欢该类型为CrdRange
,但它已使用Range
而不是CrdRange
解压缩。
请注意,我也有一两个特殊实例;例如,我有一个特殊的instance Ord Coord
。
答案 0 :(得分:2)
首先想到的是GeneralizedNewtypeDeriving
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Data.Bifunctor
newtype Coord a b = Coord (a,b) deriving Bifunctor
newtype Range a b = Range (a,b) deriving Bifunctor
type CrdRange = Range (Coord Int Int) (Coord Int Int)
答案 1 :(得分:1)
如果您正在使用镜头或microlens库,也许您可以定义coordToTuple :: Traversal' Coord (Int,Int)
形式的镜头/遍历,然后使用over
功能比如over coordToTuple (first someFunction) someCoord
。
为了避免记住多个镜头的名称,您可以定义一个多参数类型类,如
class MonoPair c a | c -> a where
monoPair :: Traversal' c (a,a)
并为您的类型定义实例。
替代想法:从线性中将您的类型定义为V2
周围的新类型。这只有在你的类型表现得像矢量时才有意义。 V2
不是bifunctor,但您可以使用GeneralizeNewtypeDeriving
派生R1
和R2
类型来获取/设置组件。
为避免模式匹配时出现笨拙的括号,请定义辅助pattern synonyms,如
pattern CoordV2 x y = Coord (V2 x y)