如何将该实例方法定义移至类默认值?

时间:2018-07-24 15:49:37

标签: haskell types type-families

请考虑此类以及示例实例。

目的是提供一种类型级别开关,该类型级别开关允许将基本类型(在这种情况下为Int转换为经过验证的谓词子类型,以供将来使用)。当然,该类在某种程度上是人为设计的,但是我从实际代码中提取了该类,并且将使用更有用的方法填充该类,除非遇到麻烦。

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE TypeApplications #-}

module Collection where

import Data.Tagged

-- $setup
--
-- λ :set -XTypeApplications

class Collected phantom
  where
    type Element phantom = r | r -> phantom
    type Element phantom = Tagged phantom Int

    type Collection phantom = r | r -> phantom
    type Collection phantom = Tagged phantom [Int]

    collection :: Collection phantom

    inCollection :: Int -> Maybe (Element phantom)

data Primes

instance Collected Primes
  where
    type Element Primes = Tagged Primes Int
    type Collection Primes = Tagged Primes [Int]

    collection = Tagged [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

    -- inCollection :: Int -> Maybe (Element Primes)
    inCollection element
        | element `elem` unTagged (collection @Primes) = Just $ Tagged element
        | otherwise = Nothing

-- ^
-- λ inCollection @Primes 7
-- Just (Tagged 7)
-- λ inCollection @Primes 8
-- Nothing

(这是一个可运行的代码,具有按书面要求通过的repl测试。)

我将处理同一个基本类型上的几个子类型,这些子类型仅因collection的定义而不同,而证明方法是始终查找。因此,没有理由没有该方法的默认代码。但是,我无法设计这样的代码。我的第一个草稿无法进行类型检查,而第二个草稿经过调整后可以运行,但似乎没有终止。

这是初稿:

...
{-# LANGUAGE DefaultSignatures #-}
...

class Collected phantom
...
    inCollection :: Int -> Maybe (Element phantom)
    default inCollection :: ( Element phantom    ~ Tagged phantom  Int
                            , Collection phantom ~ Tagged phantom [Int] )
                         => Int -> Maybe (Element phantom)
    inCollection element
        | element `elem` unTagged collection = Just $ Tagged element
        | otherwise = Nothing
...

这是第二个:

...
{-# LANGUAGE ScopedTypeVariables #-}
...

class Collected phantom
...
    inCollection :: ...
    default inCollection :: ...
    inCollection ...
      where
        collection = (collection :: Collection phantom)

(仅显示添加的部分。实例中相应的方法定义已删除。在第二稿中,除了编译指示外,唯一的添加是尝试键入collection的最后一行。 )

出什么问题了?该怎么办?

1 个答案:

答案 0 :(得分:3)

似乎可以进行以下操作。这个想法是在默认情况下以正确的类型实例化collection(使用collection @phantom),该类型也需要ScopedTypeVariables

更新:我现在看到这是您尝试进行的第二次尝试。问题在于您的where子句定义了一个无限循环,因为RHS上的collection与LHS上绑定的collection相同(请适当插入facepalm)。

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

module Collection where

import Data.Tagged

class Collected phantom
  where
    type Element phantom = r | r -> phantom
    type Element phantom = Tagged phantom Int

    type Collection phantom = r | r -> phantom
    type Collection phantom = Tagged phantom [Int]

    collection :: Collection phantom

    inCollection :: Int -> Maybe (Element phantom)
    default inCollection :: ( Collection phantom ~ Tagged phantom [Int]
                            , Element phantom ~ Tagged phantom Int)
                            => Int -> Maybe (Element phantom)
    inCollection element
        | element `elem` unTagged (collection @phantom) = Just $ Tagged element
        | otherwise = Nothing

data Primes

instance Collected Primes
  where
    type Element Primes = Tagged Primes Int
    type Collection Primes = Tagged Primes [Int]

    collection = Tagged [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]