有单元课吗?它会有用吗?

时间:2011-09-17 00:11:58

标签: haskell

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

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

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

3 个答案:

答案 0 :(得分:9)

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

目前还不清楚这样的类甚至意味着什么,这使得实际使用起来很困难,因为不可避免地会遇到有多种默认值选择的类型,如果它不是立即清楚实例提供了哪一个,你几乎失去了首先拥有课程的所有好处。

一些例子:

  • 对于Monoid个实例,您显然希望identity元素是默认值。但是现在你又回到了这么多类型的问题,这个类型有两个或更多合理的Monoid个实例。默认Integer是0还是1?对于Monoid,标准库使用newtype包装器,但这些包装笨拙并且难以使用包装类型 - 使用Monoid它可以正常工作,因为您可以访问{{ 1}}等等,但你不能只用默认值任何有趣的东西。

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

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

  • ()怎么样?如果以上都不适用,您可以使用Bounded。但是上面的一些类型也可能是minBound,所以如果它们的默认值不是最小值,你就会感到困惑。

基本上,有足够的重叠,它似乎才有意义......但实际上,你在这里至少考虑了三种不同类型的类,并试图统一它们可能不是尽管看起来很有帮助。


如果你可以更好地解决问题,并对“默认”值进行清晰,一致的语义解释,不用重新发明Bounded或其他现有类,这样类型类很容易使用而不必停下来思考什么“默认”被选中,太棒了!但是我不希望它成功。

也就是说,任何标准类型类都没有涵盖的明显合理的案例是像Monoid这样的单身人士。大多数时候这些都不是非常有用 - 显而易见的原因! - 这可能就是为什么没有这样的课程。但是,这样一个类极其有用的地方就是当你在做涉及类型级恶作剧的事情时,因为这样的类型在类型和术语级别都代表一个值 - 所以这类类的类允许你自由地操作类型级值,然后想出与它一起使用的术语,因此你可以将它传递给其他一些函数,例如,可以根据它选择一个类型类实例。出于这个原因,我有a class along those lines in my perpetually-incomplete type-hackery library,例如:

()

我怀疑这个类在任何其他环境中都非常有用。

答案 1 :(得分:6)

您正在寻找某种Default类型的类。虽然“默认”应该是什么的语义是值得商榷的(我建议你接受CA McCanns在那里的有价值的评论),你可以从一个名为{{3}的常用软件包中获得一个Default类。 }。

课程是:

-- | A class for types with a default value.
class Default a where
    -- | The default value for this type.
    def :: a

答案 2 :(得分: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