Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何在需要类型构造函数而不是具体类型的类实例中统计类约束?_Haskell_Type Constructor - Fatal编程技术网

Haskell 如何在需要类型构造函数而不是具体类型的类实例中统计类约束?

Haskell 如何在需要类型构造函数而不是具体类型的类实例中统计类约束?,haskell,type-constructor,Haskell,Type Constructor,我目前在of中,我已经到达了Functor类型类的部分。在上述章节中,作者举例说明了如何将不同类型作为类的实例(例如Maybe、自定义树类型等)。看到这一点,我决定(为了好玩和练习)尝试为该类型实现一个实例;当然,在所有这一切中,我们都忽略了 实际的实例本身非常简单,我这样写: instance Functor Set.Set where fmap f empty = Set.empty fmap f s = Set.fromList $ map f (Set.elems s) 但

我目前在of中,我已经到达了
Functor
类型类的部分。在上述章节中,作者举例说明了如何将不同类型作为类的实例(例如
Maybe
、自定义
类型等)。看到这一点,我决定(为了好玩和练习)尝试为该类型实现一个实例;当然,在所有这一切中,我们都忽略了

实际的实例本身非常简单,我这样写:

instance Functor Set.Set where
  fmap f empty = Set.empty
  fmap f s = Set.fromList $ map f (Set.elems s)  
但是,由于我碰巧使用了该函数,因此引入了一个类约束,要求
集合
中使用的类型为
Ord
,编译器错误对此进行了解释:

Error occurred
ERROR line 4 - Cannot justify constraints in instance member binding
*** Expression    : fmap
*** Type          : Functor Set => (a -> b) -> Set a -> Set b
*** Given context : Functor Set
*** Constraints   : Ord b
见:

我尝试对实例施加约束,或向
fmap
添加类型签名,但都没有成功(都是编译器错误)

在这种情况下,如何满足约束条件?有什么可能的办法吗

提前感谢!:)

不幸的是,对于标准的
Functor
类,没有简单的方法可以做到这一点。这就是为什么默认情况下,
Set
不附带
Functor
实例的原因:您不能编写一个实例

这是一个问题,有一些建议的解决方案(例如,以不同的方式定义
Functor
类),但我不知道在如何最好地处理这一问题上是否存在共识

我认为一种方法是重写
函子
类,用以具体化新
函子
类的实例可能具有的附加约束。这将允许您指定
Set
必须包含
Ord
类中的类型

另一种方法只使用多参数类。我只能找到关于为
Monad
类执行此操作的文章,但是使
Set
成为
Monad
的一部分与使其成为
Functor
的一部分面临相同的问题。它叫

这里使用多参数类的基本要点如下:

class Functor' f a b where
  fmap' :: (a -> b) -> f a -> f b

instance (Ord a, Ord b) => Functor' Data.Set.Set a b where
  fmap' = Data.Set.map
基本上,您在这里所做的就是使
集中的类型也成为类的一部分。这样,您就可以在编写该类的实例时约束这些类型

此版本的
Functor
需要两个扩展:
MultiParamTypeClasses
FlexibleInstances
。(您需要第一个扩展来定义类,第二个扩展来定义
Set
的实例)


对此进行了很好的讨论。

这是不可能的。
Functor
类的用途是,如果您有
Functor f=>fa
,则可以用任何您喜欢的内容替换
a
。不允许该类约束您只返回这个或那个。由于
Set
要求其元素满足某些约束(实际上,这不是实现细节,而是集合的基本属性),因此它不满足
Functor
的要求

正如在另一个答案中提到的,有一些方法可以开发一个类,比如
Functor
,它确实以这种方式约束您,但它实际上是一个不同的类,因为它为类的用户提供了更少的保证(您不能将它与您想要的任何类型参数一起使用),作为交换,它将适用于更广泛的类型。毕竟,这是定义类型属性的经典权衡:您想要满足的类型越多,它们必须满足的越少

(另一个有趣的例子是
MonadPlus
类。特别是,对于每个实例
MonadPlus TC
,您可以创建一个实例
Monoid(tca)
,但您不能总是反过来。因此,
Monoid(可能是a)
实例可能不同于
MonadPlus
实例,因为前者可以限制
a
,但后者不能。)


约束函子类的一个问题是,我们失去了很多能力。特别是对于应用函子,我们通常希望将函数放入其中。然而,在许多情况下,不可能为函数提供我们感兴趣的类的一般实例。
{-# LANGUAGE GADTs #-}

data CYSet a where
    CYSet :: (Ord a) => Set.Set a -> (a -> b) -> CYSet b

liftCYSet :: (Ord a) => Set.Set a -> CYSet a
liftCYSet s = CYSet s id

lowerCYSet :: (Ord a) => CYSet a -> Set.Set a
lowerCYSet (CYSet s f) = Set.fromList $ map f $ Set.elems s

instance Functor CYSet where
  fmap f (CYSet s g) = CYSet s (f . g)

main = putStrLn . show
  $ lowerCYSet
  $ fmap (\x -> x `mod` 3)
  $ fmap abs
  $ fmap (\x -> x - 5)
  $ liftCYSet $ Set.fromList [1..10]
-- prints "fromList [0,1,2]"