约束实例方法

时间:2015-01-15 21:48:03

标签: haskell

我想写:

{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE DatatypeContexts #-}

data Ord a => S a = ...
toList :: Ord a => S a -> [a]
fromList :: Ord a => [a] -> S a

instance Functor S where
  fmap :: (Ord a, Ord b) => (a -> b) -> S a -> S b
  fmap f = fromList . fmap f . toList

但GHC一直在打击我

  

方法签名与类

不匹配

问题:

  • 你知道解决方法吗?
  • 此限制解决了什么问题?

1 个答案:

答案 0 :(得分:5)

你不能,简单地说。定义了Functor类,使其必须适用于所有a -> b,而不仅仅是a -> b。不过,您可以定义自己的FunctorOrd

class FunctorOrd f where
    fmapOrd :: (Ord a, Ord b) => (a -> b) -> f a -> f b

然而,这可能不是你想要的。我猜你是否想要构建某种类似集合的结构,在内部使用二叉树来保持唯一性。如果我要做像

这样的事情会发生什么
s :: S Int
s = fromList [1..100]

t :: S Bool
t = fmap even s

这只会将even应用于集合中的每个Int,它根本无法改变结构,只包含它所包含的内容。你最好写一个像

这样的函数
smap :: (Ord a, Ord b) => (a -> b) -> S a -> S b
smap f = fromList . map f . toList

或者可能更高效,但仍然能够改变结构本身,而不仅仅是价值。

这并不是一个限制,它必须满足Functor法律才能使fmap行为正常。这可能看起来不是什么大问题,但是请查看各种ListT实施的有争议的历史以及它们如何不满足单一法则。