通过类型别名保持表达能力(我应该使用多少类型别名?)

时间:2017-01-18 19:48:17

标签: haskell

这主要是一个风格问题(所以对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 Coordtype 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

2 个答案:

答案 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派生R1R2类型来获取/设置组件。

为避免模式匹配时出现笨拙的括号,请定义辅助pattern synonyms,如

pattern CoordV2 x y = Coord (V2 x y)