Elm 设计多态API

Elm 设计多态API,elm,Elm,我有一个尺度的概念,它在输入域和输出范围之间转换。然而,有几种类型的天平;每个都支持可能操作的子集,并存储稍微不同的范围 例如: 具有域(浮点,浮点)和范围(浮点,浮点)的连续刻度(刻度(浮点,浮点)(浮点,浮点))支持: convert:Continuous->Float->Float将值从域转换为范围 invert:Continuous->Float->Float将一个值从范围转换回域 domain:Continuous->(Float,Float)返回域 ticks:Continuous

我有一个尺度的概念,它在输入域和输出范围之间转换。然而,有几种类型的天平;每个都支持可能操作的子集,并存储稍微不同的范围

例如:

具有域
(浮点,浮点)
和范围
(浮点,浮点)
连续
刻度(
刻度(浮点,浮点)(浮点,浮点)
)支持:

  • convert:Continuous->Float->Float
    将值从域转换为范围
  • invert:Continuous->Float->Float
    将一个值从范围转换回域
  • domain:Continuous->(Float,Float)
    返回域
  • ticks:Continuous->List Float
    返回适合在轴上绘制的值
顺序
刻度有一个
(Float,Float)
域和一个来自
Float->a
的函数,通常存储范围没有多大意义

  • convert:Sequential a->Float->a
    将值从域转换为范围
  • domain:Sequential a->(Float,Float)
    返回域
分位数
比例将采样输入域(
列表浮点
)映射到离散范围(
列表A
)。域被认为是连续的;但是,域被指定为一组离散的样本值

  • convert:Quantile a->Float->a
    将值从域转换为范围
  • invertExtent:Quantile a->a->(Float,Float)
    返回与范围对应的域的范围
如果上面的例子没有多大意义,不要担心。主要的一点是,有几种类型的对象共享一些逻辑操作,但不是全部。某些操作仅由某些类型共享,而不是由所有类型共享。对于某些类型,某些操作只有“特殊”行为,但对于其他类型,可以默认为合理的回退(即
标识
),在其他情况下,没有合理的实现。能够在所有可能的尺度或支持特定操作的所有尺度上指定通用算法也非常有用

我如何在Elm中设计这样的API


到目前为止,我有一些糟糕的想法:

  • 检查是否支持实现,否则抛出运行时错误。恶心
  • 将它们包装在模块层次结构中,调用者需要知道调用适当方法所需的包装/展开级别。对于调用方来说,这似乎非常难看,而且是一个非常难以使用的API。也无法处理所有案件
  • 具有类似于
    Scale supportsOp1 supportsOp2 supportsOp3
    的类型,其中每个类型变量都可以具有
    SupportsOp
    Doesnt
    的类型。然后我可以有一个功能,例如
    op1:Scale SupportsOp a b->c
    。这确实很有用,但是类型注释非常难看。此外,我不完全确定如何处理实际存储实际类型的范围和域的类型
  • 使用特殊类型的类。因此,对于每个调用,您必须传递一个具有适当实现的记录。这几乎奏效了。对于API的消费者来说,这有点痛苦——这有点违背了官方的建议,因为它鼓励您存储函数并传递它们
是否可以将单一类型的
缩放a
和缩放的每个子类定义为不同的构造函数

a型刻度盘
=连续(浮动,浮动)(浮动,浮动)
|顺序(浮动,浮动)(浮动->a)
|分位数(列表浮动)(浮动->a)
Sequential
Quantile
都需要类型参数,而
Continuous
则不需要,所以这有点难看。为其中一个值设置
Continuous
类型参数以使其更干净,这有意义吗

如果您能够使用单个类型,那么处理该类型将成为一系列
case
语句

convert:Scale a->Float->a
换算刻度值=
病例表
连续域范围->。。。
顺序域映射器->。。。
分位数域映射器->。。。
对于不受支持的操作,您是否可以将函数签名更改为返回
可能是a
和返回
Nothing
,而不是抛出运行时错误?虽然您无法在函数调用之前确定支持度,但至少必须显式处理返回的
Nothing
值,这是事后检查支持度的方法

invertExtent:Scale a->a->Maybe(Float,Float)
反广度刻度=
病例表
连续->无
顺序->无
分位数域映射器->仅(…)
我认为这是乍得答案的延伸,它考虑了你对它的评论。

您肯定是对的,自由使用
可能
s应该表明存在设计问题。然而,更进一步看,似乎你正在努力将逻辑上不同的想法结合起来。似乎最适合Elm生态系统的设计实际上是在API级别将这些东西分开

考虑
结果
可能
,以及
任务
它们提供了类似的功能,因此,它们提供了非常相似的接口(即
映射
然后
)。有一种非常明显的方法可以在它们之间转换,但是没有多态性,因为它们实际上是不同的想法,具有不同的用例

我认为这是关键:当您对多个表达式具有相同的内容时,请使用类型联合。如果你不是certa