Jim*_*ies 5 haskell types typeclass
我有以下类型类
class MyClass c where
aFunction :: c -> Bool
Run Code Online (Sandbox Code Playgroud)
和两个不同数据类型的两个实例
data MyDataType1 = MyDataType1
instance MyClass MyDataType1 where
aFunction c = True
data MyDataType2 = MyDataType2
instance MyClass MyDataType2 where
aFunction c = False
Run Code Online (Sandbox Code Playgroud)
我想写一个函数一个函数,它接受类型类MyClass的两个参数(可能是相同的数据类型或者可能是不同的并返回其中一个.我正在努力找出这个的类型签名,我想我可能采取错误的方法.
这是正确的吗?如果不是我应该使用什么呢?
chooseOne :: (MyClass a, MyClass b) => a -> b -> ?
chooseOne x y = if (aFunction x) then x else y
Run Code Online (Sandbox Code Playgroud)
And*_*ewC 11
您的返回值可以是任何一种类型,因此编译器会抱怨,除非您为两者使用相同的类型,给出
chooseOne :: (MyClass a, MyClass a) => a -> a -> a
Run Code Online (Sandbox Code Playgroud)
这不是你的意思.
要将两种可能不同的类型合并为一种,您可以使用Either数据类型:
data Either a b = Left a | Right b
Run Code Online (Sandbox Code Playgroud)
所以你会的
chooseOne :: (MyClass a, MyClass b) => a -> b -> Either a b
chooseOne x y = if (aFunction x) then Right x else Left y
Run Code Online (Sandbox Code Playgroud)
但我宁愿写那个
chooseOne :: (MyClass a, MyClass b) => a -> b -> Either a b
chooseOne x y | aFunction x = Right x
| otherwise = Left y
Run Code Online (Sandbox Code Playgroud)
您正在编写的函数在Haskell中是不可能的 - 返回类型必须在编译时修复并且已知.因此,要写出你感兴趣的东西,你需要一个Either
.
chooseOne :: (MyClass a, MyClass b) => a -> b -> Either a b
chooseOne x y = if (aFunction x) then Left x else Right y
Run Code Online (Sandbox Code Playgroud)
最后,即使是在动态语言,你必须有一些代码,同时处理了a
与b
类型相同.这"消除" Either
并体现在功能中Data.Either.either
either :: (a -> c) -> (b -> c) -> Either a b -> c
either f _ (Left a) = f a
either _ g (Right b) = g b
Run Code Online (Sandbox Code Playgroud)
为了您的具体情况,因为这两个a
和b
是的情况下MyClass
,感觉就像我们可以做一个稍微更方便的去除功能
eitherOfMyClass :: (MyClass a, MyClass b) => (a -> b) -> Either a a' -> b
eitherOfMyClass f (Left a) = f a
eitherOfMyClass f (Right a') = f a'
Run Code Online (Sandbox Code Playgroud)
但这实际上不会打字!如果仔细查看可能找到问题的类型 - 我们传入的处理函数是专用的a
,因此不能应用于类型的Right
一侧.因此我们需要使用,一个启用的扩展.Either
b
forall
LANGUAGE RankNTypes
{-# LANGUAGE RankNTypes #-}
eitherOfMyClass :: (MyClass a, MyClass b) =>
(forall x. MyClass x => (x -> c)) -> Either a b -> c
eitherOfMyClass f (Left a) = f a
eitherOfMyClass f (Right b) = f b
Run Code Online (Sandbox Code Playgroud)
这可以确保f
您传入的任何函数eitherOfMyClass
对于任何实例都是通用的MyClass
,因此可以应用于您a
和b
您的任何实例Either
.