Haskell:在声明一个类时,如何使用不在构造函数中的类型变量?

sqd*_*sqd 1 haskell

我想定义一个函数,<-?来检查一个元素是否在list/set/map中.

module Test where
import qualified Data.Map as Map
import qualified Data.Set as Set

class Memberable a where
    (<-?) :: b -> a -> Bool
instance Memberable [x] where
    (<-?) = elem
instance Memberable (Map.Map k v) where
    (<-?) = Map.member
instance Memberable (Set.Set x) where
    (<-?) = Set.member
Run Code Online (Sandbox Code Playgroud)

b类声明中的类型变量应该是我想要检查的元素的类型.但是,这对Haskell不起作用.

Test.hs:8:13:
    Couldn't match type 'b' with 'x'
      'b' is a rigid type variable bound by
          the type signature for (<-?) :: b -> [x] -> Bool at Test.hs:8:5
      'x' is a rigid type variable bound by
          the instance declaration at Test.hs:7:10
    Expected type: b -> [x] -> Bool
      Actual type: b -> [b] -> Bool
    Relevant bindings include
      (<-?) :: b -> [x] -> Bool (bound at Test.hs:8:5)
    In the expression: elem
    In an equation for '<-?': (<-?) = elem
Run Code Online (Sandbox Code Playgroud)

我如何b在类声明中使用,但仍然使类型重合?

Car*_*ten 9

运用 TypeFamilies

问题是你必须以某种方式连接b你的集合(其中的元素) - 有几种方法可以做到这一点,但我认为一个相当不错的方法是使用TypeFamilies:

{-# LANGUAGE TypeFamilies #-}

module Test where

import qualified Data.Map as Map
import qualified Data.Set as Set

class Memberable a where
  type ElemT a :: *
  (<-?) :: (ElemT a) -> a -> Bool

instance Eq x => Memberable [x] where
    type ElemT [x] = x
    (<-?) = elem

instance Ord k => Memberable (Map.Map k v) where
    type ElemT (Map.Map k v) = k
    (<-?) = Map.member

instance Ord x => Memberable (Set.Set x) where
    type ElemT (Set.Set x) = x
    (<-?) = Set.member
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我在类中添加了一个附加type 成员,该成员将保存所使用元素的类型(因此您可以(<-?)在下一行中使用它们).

我还为你的实例添加了所需的约束 - 那些实际上来自使用的函数,比如elem,Map.memberSet.member.


运用 MultiParamTypeClasses

这是@dfeuer暗示的(或者我认为):

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

module Test where

import qualified Data.Map as Map
import qualified Data.Set as Set

class Memberable e a where
  (<-?) :: e -> a -> Bool

instance Eq x => Memberable x [x] where
    (<-?) = elem

instance Ord k => Memberable k (Map.Map k v) where
    (<-?) = Map.member

instance Ord x => Memberable x (Set.Set x) where
    (<-?) = Set.member
Run Code Online (Sandbox Code Playgroud)

备注:

我认为使用这种方法你也可能想要添加它FunctionalDependency,因为你明确地在集合a和它的元素之间有这样的依赖关系e;)

{-# LANGUAGE FunctionalDependencies #-}

class Memberable e a | a -> e where
  (<-?) :: e -> a -> Bool
Run Code Online (Sandbox Code Playgroud)

  • 你几乎肯定想要mptc的fundeps.虽然睡觉时间对我来说! (2认同)