如何在这里避免显式类型签名?

时间:2012-10-17 07:20:41

标签: haskell typeclass

class Listy a b where
   fromList :: [b] -> a
   toList :: a -> [b]
   lifted :: ([b] -> [b]) -> (a -> a) 
   lifted f = fromList . f . toList

data MyString = MyString { getString :: String } deriving Show

instance Listy MyString Char where
  toList = getString
  fromList = MyString

现在我需要写一下,例如lifted (reverse::(String -> String)) (MyString "Foobar")。有没有诀窍可以避免需要类型签名?

2 个答案:

答案 0 :(得分:11)

基本上问题是设置a的类型并不能告诉编译器b的类型是什么。您可能,因为该类只有一个实例(其中aMyStringbChar),但任何人都可以随时添加新实例。因此,只有一个实例现在的事实无助于编译器决定您想要的类型。

解决方法是使用功能依赖关系或类型系列。后者是较新的解决方案,旨在最终“替换”前者,但现在两者仍然得到完全支持。 FD是否会消失还有待观察。无论如何,FDs:

class Listy a b | a -> b where ...

基本上这表示“每个a只能有一个类实例”。换句话说,一旦您知道a,就可以随时确定b。 (但不是相反。)该课程的其余部分看起来像以前一样。

另一种选择是TF:

class Listy a where
  type Element a :: *
  ...

instance Listy MyString where
  type Element MyString = Char
  ...

现在,它被称为b而不是被称为Element a的第二种类型。单词Element就像一个类方法,它采用listy类型并返回相应的元素类型。然后你可以做

instance Listy ByteString where
  type Element ByteString = Word8
  ...

instance Listy [x] where
  type Element [x] = x
  ...

instance Ord x => Listy (Set x) where
  type Element (Set x) = x
  ...

等等。 (并非Listy对于上述所有类型都有意义;这些只是如何定义类的示例。)

答案 1 :(得分:5)

您可以尝试-XFunctionalDependencies

class Listy a b | a -> b where
   fromList :: [b] -> a
   toList :: a -> [b]
   lifted :: ([b] -> [b]) -> (a -> a) 
   lifted f = fromList . f . toList