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
Run Code Online (Sandbox Code Playgroud)
现在我需要写例如lifted (reverse::(String -> String)) (MyString "Foobar").是否有诀窍避免需要类型签名?
Mat*_*hid 11
本质上问题是设置类型a并不告诉编译器它是什么类型b.你可能会认为,既然只有一个类的实例(其中a是MyString和b是Char),但任何人都可以随时添加新的实例.因此,事实上,只有一个实例,现在并不能帮助编译器决定你想要什么类型.
对此的解决方案是使用功能依赖关系或类型系列.后者是较新的解决方案,旨在最终"替换"前者,但现在两者仍然得到完全支持.FD是否会消失还有待观察.无论如何,FDs:
class Listy a b | a -> b where ...
Run Code Online (Sandbox Code Playgroud)
基本上这说"每个人只能有一个类实例a".换句话说,一旦你知道a,你总能确定b.(但不是反过来.)班上的其他人看起来像以前一样.
替代方案是TF:
class Listy a where
type Element a :: *
...
instance Listy MyString where
type Element MyString = Char
...
Run Code Online (Sandbox Code Playgroud)
现在调用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
...
Run Code Online (Sandbox Code Playgroud)
等等.(Listy对于上面的所有类型来说,这不一定有意义;这些只是如何定义类的示例.)
您可以尝试-XFunctionalDependencies
class Listy a b | a -> b where
fromList :: [b] -> a
toList :: a -> [b]
lifted :: ([b] -> [b]) -> (a -> a)
lifted f = fromList . f . toList
Run Code Online (Sandbox Code Playgroud)