模糊类型类在函数中返回?

时间:2016-05-01 11:36:44

标签: class haskell

我正在制作一个String Parser,而我这样做的方式并不是最优的,因为它多次遍历String。我在Haskell遇到了一些我认为很奇怪的东西。

 type LeftoverString = String
type Match = String

class Parser pars where
    findMatch::pars -> String -> (Match,LeftoverString)
    tokenName::pars -> String
    isRecursive::pars -> Bool
    recursiveParsers:: Parser p => pars -> [[p]]
    recursiveFromMatch:: pars -> String -> String
    isRecursive x = False
    recursiveParsers x = []
    recursiveFromMatch x y = y

type TokenName = String
data ParseTree = TokenLeaf Match TokenName | TokenNode TokenName [ParseTree] deriving Show

findFirstMatch::Parser a => [a] -> String ->(a,Match,LeftoverString)
findFirstMatch [] _                             = error "could not match String"
findFirstMatch (x:xs) str   | match /= ""       = (x,match,leftovers)
                            | otherwise         = findFirstMatch xs str
                                where
                                    (match,leftovers) = findMatch x str

generateTree::Parser a => a -> String -> ParseTree
generateTree pars str = head $ generateTree' [[pars]] str

test::Parser a => a -> [[a]]
test x = recursiveParsers x

generateTree'::Parser a => [[a]] -> String -> [ParseTree]
generateTree'  []    _                          = []
generateTree' (x:xs) str | isRecursive parser   = recTok:parseTreeRest
                         | otherwise            = leafTok:parseTreeRest
                    where 
                        (parser,match,leftovers)=findFirstMatch x str
                        tok = tokenName parser
                        parseTreeRest = (generateTree' xs leftovers)
                        recTok = TokenNode tok $ generateTree' (test parser) (recursiveFromMatch parser match)
                        leafTok = TokenLeaf match tok

可以看出,Parser中的recursiveParsers返回一个Parser实例列表列表

在代码中你看到了:

test::Parser a => a -> [[a]]
test x = recursiveParsers x

这用于recTok中generateTree'的位置 可以看出,test(基本上)是recursiveParsers x

的同义词

然而 - 在哪里,如果我替换:

recTok = TokenNode tok $ generateTree' (test parser) (recursiveFromMatch parser match)

recTok = TokenNode tok $ generateTree' (recursiveParsers parser) (recursiveFromMatch parser match)

编译器会生成不明确类型的错误。

错误是:

StringParser.hs:42:50:
    Could not deduce (Parser a0) arising from a use of generateTree'
    from the context (Parser a)
      bound by the type signature for
                 generateTree' :: Parser a => [[a]] -> String -> [ParseTree]
      at StringParser.hs:34:16-57
    The type variable `a0' is ambiguous
    In the second argument of `($)', namely
      `generateTree'
         (recursiveParsers parser) (recursiveFromMatch parser match)'
    In the expression:
      TokenNode tok
      $ generateTree'
          (recursiveParsers parser) (recursiveFromMatch parser match)
    In an equation for `recTok':
        recTok
          = TokenNode tok
            $ generateTree'
                (recursiveParsers parser) (recursiveFromMatch parser match)

为什么编译器需要函数recursiveParsers的同义词才能工作?

第二个问题,我相信我在尝试使用Class强制解析器具有某些功能时完全做错了吗?还有另一种方法吗?

1 个答案:

答案 0 :(得分:3)

据我所知,您正在尝试使用Haskell类型类,就好像它们是OOP类一样。他们不是。

粗略地说,类型类是类型的集合。它最接近的OOP类似于Java风格的接口(不是类)。与Java接口一样,类型类本身几乎没有用,除非在其他地方有一些实现(instance s)(在Java中,我们需要一些类来实现接口)。

注意复数"实现"。大多数情况下,只有在我们能够想到满足其界面的几种方法时才使用类型类。类型类NumInt, Integer, Float, Double, ...居住; Show的课程String, Char, Bool, Int, ...

如果我们只有一个合理的实现,那么就不需要使用类型类。

在您的具体示例中:您期望您的类型类的实现(复数)是什么?

另外,我相信你误解了方法的类型

recursiveParsers:: Parser p => pars -> [[p]]

在类型类之外,可以使用签名

访问此方法
recursiveParsers:: (Parser p1, Parser p2) => p1 -> [[p2]]

我认为错误:上述意味着该方法的调用者可以将任何解析器p1更改为解析器列表[[p2]],其中 {{1} }和p1由调用者选择。特别是,意味着它返回"某些解析器"的列表列表。

对此类方法的任何调用都需要在其上下文中指定选择p2的内容。

除了这个技术事实,我认为应该重新设计整个方法。