Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Class 什么';我的解析器类的类型有什么问题?_Class_Haskell_Instance - Fatal编程技术网

Class 什么';我的解析器类的类型有什么问题?

Class 什么';我的解析器类的类型有什么问题?,class,haskell,instance,Class,Haskell,Instance,这些天我一直有一些空闲时间,所以我决定学一些哈斯克尔 为了练习,我正在翻译一个我在SCALA的一个班级里做的项目。 但我对这部分代码有问题。这很容易理解 其思想是对一些解析器进行建模,这些解析器将获取一些字符串,并将其解析为ParserOutput,该ParserOutput包含解析后的元素“output”和“余数”(无法解析的字符串部分) 我可以在不定义新类(只使用数据“MyParser”)的情况下完成这项工作,但我认为定义一个类会很有趣,这样我就可以在一个地方定义我希望解析器使用的所有方法

这些天我一直有一些空闲时间,所以我决定学一些哈斯克尔

为了练习,我正在翻译一个我在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