2016-11-06 146 views
3

我学习Haskell,所以它可能是非常微不足道的,但我会很感激如何重写它以及它如何工作的一些指针。重构在哪里条款

我有以下工作代码(使用的包:HTFParsecFlow):

{-# OPTIONS_GHC -F -pgmF htfpp #-} 
{-# LANGUAGE FlexibleContexts #-} 

module Main where 

import Test.Framework -- assertEqual, assertBool, htfMain, htf_thisModulesTests 
import Text.ParserCombinators.Parsec (eof, spaces, parse) 
import Flow ((|>)) 
import Data.Either (isLeft) 

whiteSpaces = spaces 

test_parse_whitespace = do 
    mapM_ positive [ 
     "", " ", "\t", "\n", "\r\n", " \r\n ", 
     " \t \r\n \t \n \r \t " 
    ] 
    mapM_ negative ["x", " x", "x ", " x ", "\t_\t"] 
    where 
    parser = whiteSpaces >> eof 
    parseIt = parse parser "" 
    positive str = assertEqual (parseIt str) (Right()) 
    negative str = assertBool (parseIt str |> isLeft) 

main :: IO() 
main = htfMain htf_thisModulesTests 

我增加了新的测试,具有几乎相同的,其中的一部分,所以我试图重构它是这样的:

pos_neg_case parser = do 
    return [positive, negative] 
    where 
    fullParser = parser >> eof 
    parseIt = parse fullParser "" 
    positive str = assertEqual (parseIt str) (Right()) 
    negative str = assertBool (parseIt str |> isLeft) 

test_parse_whitespace' = do 
    mapM_ positive [ 
     "", " ", "\t", "\n", "\r\n", " \r\n ", 
     " \t \r\n \t \n \r \t " 
    ] 
    mapM_ negative ["x", " x", "x ", " x ", "\t_\t"] 
    where 
    [positive, negative] = pos_neg_case whiteSpaces 

哪个不起作用(即使当我按照编译器的建议关闭lang功能时)。

Couldn't match expected type ‘[Char] -> m b0’ 
      with actual type ‘[String -> IO()]’ 
Relevant bindings include 
    test_parse_whitespace' :: m() (bound at test/Spec.hs:21:1) 
In the first argument of ‘mapM_’, namely ‘positive’ 
In a stmt of a 'do' block: 
    mapM_ positive ["", " ", "\t", "\n", ....] 

Couldn't match expected type ‘[Char] -> m b1’ 
      with actual type ‘[String -> IO()]’ 
Relevant bindings include 
    test_parse_whitespace' :: m() (bound at test/Spec.hs:21:1) 
In the first argument of ‘mapM_’, namely ‘negative’ 
In a stmt of a 'do' block: 
    mapM_ negative ["x", " x", "x ", " x ", ....] 
+1

'assertEqual'和'assertBool'来自[* HTF *](http://hackage.haskell.org/package/HTF-0.13.1。0/docs/Test-Framework-HUnitWrapper.html)包,而'(|>)'来自[* flow *](https://hackage.haskell.org/package/flow-1.0.7/docs/Flow .html),它只是'flip($)'和'(&)'的同义词。 (提及你正在使用的不那么知名的软件包会产生更清晰的问题。) – duplode

+0

@duplode哦,谢谢(我认为导入足够了)。我知道*流*在Haskellers中不太受欢迎,但* HTF *不是太?有没有更好的选择可以在没有样板的模块中运行所有的单元测试? – monnef

+0

“我认为进口就足够了” - 它们就足够了,它们提供了足够的信息来搜索并最终找到它们以及相关功能。对于这个问题的读者来说,这只是一个方便的问题。 (我没有什么可以反对你使用的任何软件包的。) – duplode

回答

0

正如你已经注意到了,问题是return您添加到:

pos_neg_case parser = do 
    return [positive, negative] 
    where -- etc. 

类型的mapM_是:

GHCi> :t mapM_ 
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m() 

positivenegative都已经具备适当的类型是功能传递给mapM,所以如果你想要pos_neg_case把它们作为列表返回,你不需要做任何事情,而不仅仅是包装在列表中。 return不是关键字;它只是一种将价值注入单一背景的功能。如果您不需要进行任何此类注射,则不需要return

P.S:引用您的答案:

但我猜解析器类型,洞,让我非常复杂啄 Text.Parsec.Prim.ParsecT s() Data.Functor.Identity.Identity a -> [s -> IO()]

这是一个很常见的模式的例子。 是一个带有不少类型变量的类型构造函数,Parser是这些变量中一些常见选项的同义词类型,它允许未明确提及它们的整数类型签名。如果您在documentation寻找它(该指数有很大帮助,在这种情况下),或在GHCI使用:info,你会发现,Parser只是意味着...

type Parser = Parsec String() 

...和Parsec,又是...

type Parsec s u = ParsecT s u Identity 

......使扩大Parser代名词给人ParsecT String() Identity,这是GHC告诉你,当你导入型孔。

+0

谢谢你的解释:)。 – monnef

0

我现在还不能确定那些单子,但我得到了它在某种程度上工作(这些_又名typeholes帮了不少忙,不知道它们)。

pos_neg_case :: Parser a -> [String -> IO()] 
pos_neg_case parser = [positive, negative] 
    where 
    fullParser = parser >> eof 
    parseIt = parse fullParser "" 
    positive str = assertEqual (parseIt str) (Right()) 
    negative str = assertBool (parseIt str |> isLeft) 

但我猜解析器类型,洞,让我非常复杂啄 - Text.Parsec.Prim.ParsecT s() Data.Functor.Identity.Identity a -> [s -> IO()]