我正在学习如何在Haskell中使用类型类。
考虑具有类型约束类函数T
的类型类f
的以下实现。
class T t where
f :: (Eq u) => t -> u
data T_Impl = T_Impl_Bool Bool | T_Impl_Int Int | T_Impl_Float Float
instance T T_Impl where
f (T_Impl_Bool x) = x
f (T_Impl_Int x) = x
f (T_Impl_Float x) = x
当我将其加载到GHCI 7.10.2时,我收到以下错误:
Couldn't match expected type ‘u’ with actual type ‘Float’ ‘u’ is a rigid type variable bound by the type signature for f :: Eq u => T_Impl -> u at generics.hs:6:5 Relevant bindings include f :: T_Impl -> u (bound at generics.hs:6:5) In the expression: x In an equation for ‘f’: f (T_Impl_Float x) = x
我在做什么/理解错误?我觉得有必要通过提供一个伴随数据构造函数和函数实现来专门化一个实例中的类型类。部分
无法匹配预期类型'
u
'实际类型'Float
'
特别令人困惑。如果u
只有Float
类型必须符合u
类型(Eq
s那样做)的约束,为什么Float
与If Not WScript.Arguments.Named.Exists("elevate") Then
CreateObject("Shell.Application").ShellExecute WScript.FullName _
, WScript.ScriptFullName & " /elevate", "", "runas", 1
WScript.Quit
End If
'Your code goes here
不匹配?
答案 0 :(得分:15)
签名
f :: (Eq u) => t -> u
表示来电者可以根据需要选择t
和u
,唯一的责任是确保u
属于Eq
类(以及t
类的T
- 在类方法中,存在隐式T t
约束。)
这并不意味着实施可以选择任何u
。
因此,来电者可以通过以下任何方式使用f
:(在课程t
中使用T
)
f :: t -> Bool
f :: t -> Char
f :: t -> Int
...
编译器抱怨说你的实现不够通用,无法涵盖所有这些情况。
Couldn't match expected type ‘u’ with actual type ‘Float’
表示"您向我提供了Float
,但您必须提供一般类型u
的值(调用方将选择u
)&#34 ;
答案 1 :(得分:8)
Chi已经指出了为什么你的代码不能编译。但它甚至不是类型问题;实际上,你的例子只有一个实例,所以它也可能是一个普通的函数,而不是一个类。
从根本上说,问题是你正在尝试做类似
的事情foobar :: Show x => Either Int Bool -> x
foobar (Left x) = x
foobar (Right x) = x
这不起作用。它会尝试使foobar
返回不同的类型,具体取决于您在运行时提供的值。但是在Haskell中,所有类型必须在编译时确定100%。所以这不起作用。
然而,可以做几件事。
首先,你可以这样做:
foo :: Either Int Bool -> String
foo (Left x) = show x
foo (Right x) = show x
换句话说,实际上是显示它,而不是返回可显示的内容。这意味着结果类型始终为String
。这意味着调用哪个版本的show
会在运行时发生变化,但这很好。代码路径在运行时可能会有所不同,它的类型不能。
你可以做的另一件事是:
toInt :: Either Int Bool -> Maybe Int
toInt (Left x) = Just x
toInt (Right x) = Nothing
toBool :: Either Int Bool -> Maybe Bool
toBool (Left x) = Nothing
toBool (Right x) = Just x
再次,这完全正常。
您可以做其他事情;不知道你为什么要这样,很难建议其他人。
作为旁注,你想要停止思考它,就像它的面向对象编程一样。事实并非如此。它需要一种新的思维方式。特别是,除非你真的需要一个类型类,否则不要使用它。 (我意识到这个特殊的例子可能仅仅是学习类型课程的学习练习......)
答案 2 :(得分:0)
可以这样做:
class Eq u => T t u | t -> u where
f :: t -> u
您需要在呼叫站点上使用FlexibleContextx + FunctionalDepencencies和MultiParamTypeClasses + FlexibleInstances。或者消除类并改用数据类型,例如Gabriel展示here