【问题标题】:Can I drop the type instantiation from an instance of a class with an associated type family?我可以从具有关联类型族的类的实例中删除类型实例化吗?
【发布时间】:2018-10-14 16:50:45
【问题描述】:

我有这个代码:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE DefaultSignatures #-}

module Study where

class C a where
    type T a = r | r -> a
    pred :: T a -> Bool

    default pred :: T a ~ [a] => T a -> Bool
    pred = not . null

instance C Integer where
    type T Integer = [Integer]

它是这样工作的:

λ Study.pred [1,2,3]
True
λ Study.pred ([ ] :: [Integer])
False

我想将最小实例定义简化为:

instance C Integer

——除非我特别想偏离这个模式。

我计划拥有的大多数实例应该是默认的,使用T a ~ [a],但有些确实需要它们 拥有T 类型。我不愿意容忍许多相同的琐碎定义,例如给定的 一。可以做什么?

【问题讨论】:

  • 万一这不是一个最小化的例子:因为你在课堂上没有单独提到a(只有T a),考虑class C a where pred :: a -> Bool;它不需要花哨的扩展,并且功能同样强大(感谢您关联类型上的 r -> a 注释)。
  • @DanielWagner 即使它被严重最小化,我实际上可以使用你的建议。你看,我的班级有两种方法:“连接”,其签名中同时包含aT a,以及“隔离”,只有T a,但从来没有a。 (例如,pred 将被隔离。)现在,我可以将所有隔离方法放在一个类 C 中,然后将连接方法放在一个双参数子类 C ta => B a ta 中。

标签: haskell types type-families


【解决方案1】:

你可以只添加一个默认类型实例化:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE DefaultSignatures #-}

module Study where

data One a = One a

class C a where
    type T a = r | r -> a
    -- This looks a bit strange,
    -- because it looks like T is defined twice
    -- but that's not actually the case
    type T a = [a]
    pred :: T a -> Bool

    default pred :: T a ~ [a] => T a -> Bool
    pred = not . null

instance C Integer

instance C Char where
  type T Char = One Char
  pred = const True

*Study> :t undefined :: T Integer
undefined :: T Integer :: [Integer]
*Study> :t undefined :: T Char
undefined :: T Char :: One Char

【讨论】:

    猜你喜欢
    • 2014-10-02
    • 2022-08-10
    • 2016-01-06
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 2015-05-29
    • 2022-06-26
    • 2015-10-07
    相关资源
    最近更新 更多