6

是否存在具有单个单位值的类型的类(不确定此处的正确术语),即具有某些预定义的类型?

class Unit a where
    unit :: a

instance Unit () where
    unit = ()

instance Unit (Maybe a) where
    unit = Nothing

...适用于所有 Monoids、MonadPlus 等。

我想这个类的另一个名字可能是Default. 这对我来说最近两次有用。

可能没有说服力的例子:

extract :: (Unit r)=> Reader r a -> a
extract r = runReader r unit

这存在吗?其他人认为它可能有用吗?

4

3 回答 3

9

是的,它可能会很有用。事实上,它的所有稍微不兼容的版本都会很有用!这有点问题。

甚至不清楚这样一个类意味着什么,这使得它很难实际使用,因为不可避免地你会遇到有多个默认值选择的类型,如果不能立即清楚实例提供了哪一个,那么你很漂亮很多人首先失去了上课的所有好处。

几个例子:

  • 例如Monoid,您显然希望标识元素是默认值。但是现在你又回到了具有两个或更多合理Monoid实例的这么多类型的问题上。默认是Integer0 还是 1?对于Monoid,标准库使用newtype包装器,但这些包装器很笨拙,并且很难使用包装器类型 -Monoid它可以正常工作,因为您可以访问mconcat等等,但是您不能仅使用默认值来做任何有趣的事情。

  • 对于Functor具有“空”值的 -like 类型,这给出了明显的默认值。这就是正在做的事情......MonadPlus并且Alternative也与 重叠Monoid,如果记忆对我有用,那么至少有一种类型,这三个实例并不相同。当有多个选择时,你会选择哪一个?考虑列表:您可以盲目地附加它们,给一个任意的Monoid,以空列表作为标识;但是对于你的列表,Monoids你也可以zipWith mappend,给出一个提升的幺半群repeat mempty作为身份。许多仿函数有类似的Monoid实例,但并不总是两者兼有——所以无论你选择哪个列表,你都会在概念上与其他一些不一致Functor

  • 对于像这样的单位类型(),选择默认值并不难!但是枚举呢?选择第一个构造函数有意义吗?有时,但并非总是如此。使用该课程的人将如何知道?

  • 怎么样Bounded?如果以上都不适用,您可以使用minBound. 但是上面的一些类型也可以Bounded,所以如果它们的默认值不是它们的最小值,你会混淆问题。

基本上,有足够多的重叠似乎是有道理的......但实际上,您至少已经想到了三种不同的类型类,并且尝试统一它们可能不像最初看起来那么有用。


如果您可以更好地确定事情并给出“默认”值的清晰、一致的语义解释,而无需重新发明Monoid或另一个现有的类,这样类型类就易于使用,而无需停下来思考“默认”被选中,太棒了!但我不希望让它发挥作用。

也就是说,任何标准类型类都没有涵盖的一个明显合理的情况是像(). 大多数情况下,这些并不是很有用——原因很明显!——这可能就是为什么没有这样的课程。但是,这样一个类非常有用的一个地方是,当你在做一些涉及类型级别恶作剧的事情时,因为这样的类型在类型和术语级别上都代表一个值——所以这样的类型的类可以让你自由操作类型级别的值,然后想出与之相关的术语,因此您可以将其传递给其他函数,例如,基于它选择类型类实例。出于这个原因,我在我的永远不完整的类型黑客库中有一门类似的课程,例如:

class TermProxy t where 
    term :: t

-- This makes explicit the lexical pun of () having type ().
instance TermProxy () where 
    term = ()

instance (TermProxy a, TermProxy b) => TermProxy (a, b) where 
    term = (term, term)

不过,我怀疑这样的课程在任何其他情况下都非常有用。

于 2011-09-17T00:49:17.847 回答
6

您正在寻找某种Default类型的类。虽然“默认”的语义值得商榷(我建议您接受 CA McCanns 对他的宝贵意见的回答),但您可以Default从一个相当常用的包中获取一个类,称为data-default.

课程是:

-- | A class for types with a default value.
class Default a where
    -- | The default value for this type.
    def :: a
于 2011-09-17T00:51:52.020 回答
3

如果你想避免一个新的类,你可以根据 Enum 类来定义单位:

unit :: Enum a => a
unit = toEnum 0

或者使用 Bounded 类可能会更好:

unit :: Bounded a => a
unit = minBound

这两种方法都会产生单元类型的预期结果(并且最有可能产生任何其他单一构造函数类型):

*Main> unit :: ()
()

与 data-default 类(在另一个答案中提到)相比的缺点是实例较少,特别是没有为 [a] 返回 [] 的实例。此外,结果也不是您对某些类型的期望,特别是如果您使用 minBound:

*Main> unit :: Int
-2147483648

*Main> unit :: Char
'\NUL'

*Main> unit :: Bool
False
于 2011-09-18T01:22:57.167 回答