Class 什么';我的解析器类的类型有什么问题?
这些天我一直有一些空闲时间,所以我决定学一些哈斯克尔 为了练习,我正在翻译一个我在SCALA的一个班级里做的项目。 但我对这部分代码有问题。这很容易理解 其思想是对一些解析器进行建模,这些解析器将获取一些字符串,并将其解析为ParserOutput,该ParserOutput包含解析后的元素“output”和“余数”(无法解析的字符串部分) 我可以在不定义新类(只使用数据“MyParser”)的情况下完成这项工作,但我认为定义一个类会很有趣,这样我就可以在一个地方定义我希望解析器使用的所有方法Class 什么';我的解析器类的类型有什么问题?,class,haskell,instance,Class,Haskell,Instance,这些天我一直有一些空闲时间,所以我决定学一些哈斯克尔 为了练习,我正在翻译一个我在SCALA的一个班级里做的项目。 但我对这部分代码有问题。这很容易理解 其思想是对一些解析器进行建模,这些解析器将获取一些字符串,并将其解析为ParserOutput,该ParserOutput包含解析后的元素“output”和“余数”(无法解析的字符串部分) 我可以在不定义新类(只使用数据“MyParser”)的情况下完成这项工作,但我认为定义一个类会很有趣,这样我就可以在一个地方定义我希望解析器使用的所有方法
data ParserOutput a =
Failure | Success { output :: a, remainder :: String }
deriving (Show)
data MyParser t = MyParser (String -> ParserOutput t)
class Parser p where
parse :: p -> String -> ParserOutput t
instance Parser (MyParser t) where
parse (MyParser parserDefinition) = parserDefinition
我得到的错误是:
*无法将类型't1'与't'匹配
`t1'是一个刚性类型变量,由
以下项的类型签名:
解析::forall t1。MyParser t->String->ParserOutput t1
在
`t'是一个刚性类型变量,由
实例声明
在
预期类型:字符串->解析路由输出t1
实际类型:String->ParserOutput t
*在表达式中:parserDefinition
在“parse”的等式中:
parse(MyParser parserDefinition)=parserDefinition
在“Parser(MyParser t)”的实例声明中
*相关绑定包括
parserDefinition::String->ParserOutput t
(订于……)
parse::MyParser t->String->ParserOutput t1
(订于……)
类型签名
parse :: p -> String -> ParserOutput t
表示parse
可以与调用者选择的任何类型p
和t
一起使用
现在p
实际上受到了一些限制,因为它必须是解析器的实例,所以有效类型是
parse :: (Parser p) => p -> String -> ParserOutput t
但是t
仍然是完全免费的,与p
无关
作为函数的用户,我应该(给定解析器值px
)能够编写
( parse px "" :: ParserOutput Int,
parse px "" :: ParserOutput String,
parse px "" :: ParserOutput (Double -> Double -> [Bool])
)
同样,类型签名表示我可以在每次调用中自由地选择t
您的MyParser
实例不满足此要求。为清楚起见,让我们为类型参数使用不同的名称:
instance Parser (MyParser r) where
parse (MyParser parserDefinition) = parserDefinition
在本例中,parse
应具有类型
parse :: MyParser r -> String -> ParserOutput t
但实际类型是
parse :: MyParser r -> String -> ParserOutput r
使用parserDefinition
时,结果类型直接取决于解析器类型,但类
声明并不反映这一点
如果您真的想使用一个类来实现这一点,那么您需要明确这个关系
例如,您可以在类型构造函数MyParser
上进行抽象,而不是MyParser t
:
class Parser p where
parse :: p t -> String -> ParserOutput t
instance Parser MyParser where
parse (MyParser parserDefinition) = parserDefinition
这比您最初的尝试稍微简单一些,因为它需要通过其结果类型参数化解析器
实例
要允许使用任意解析器/结果类型,我们必须使用以下内容:
或使用:
更高种类的类也是一个基本选项,即使有点不那么通用:类解析器p where parse::p t->String->ParserOutput t
您使用类的动机似乎很弱。如果您不需要至少两个实例实例解析器SomeType
和实例解析器SomeOtherType
,使用类不是一个好主意。是的,我理解。但我一直在读有关课程的书,所以我想我可以把它们作为练习来尝试。
{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}
class Parser p t | p -> t where
parse :: p -> String -> ParserOutput t
instance Parser (MyParser t) t where
parse (MyParser parserDefinition) = parserDefinition
{-# LANGUAGE TypeFamilies #-}
class Parser p where
type Result p
parse :: p -> String -> ParserOutput (Result p)
instance Parser (MyParser t) where
type Result (MyParser t) = t
parse (MyParser parserDefinition) = parserDefinition