重构where子句

时间:2016-11-06 15:09:57

标签: haskell monads parsec

我是学习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

我正在添加一个新的测试,其中where部分几乎相同,所以我试着像这样重构它:

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 ", ....]

2 个答案:

答案 0 :(得分:0)

我仍然不确定那些monad,但我得到它以某种方式工作(那些_又名类型井帮助了很多,没有人知道它们。)

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)

但是我不得不猜测Parser类型,洞让我非常复杂 - Text.Parsec.Prim.ParsecT s () Data.Functor.Identity.Identity a -> [s -> IO ()]

答案 1 :(得分: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不是关键字;它只是一个将值注入monadic上下文的函数。如果您不需要进行任何此类注射,则不需要return

P.S。:引用你的答案:

  

但我不得不猜测Parser类型,洞让我非常复杂   Text.Parsec.Prim.ParsecT s () Data.Functor.Identity.Identity a -> [s -> IO ()]

这是一个非常常见的模式的例子。 ParsecT是一个具有相当多类型变量的类型构造函数,Parser是这些变量中一些常见选择的类型同义词,它允许更整洁的类型签名,而这些签名没有明确提及它们。如果你在documentation中查找(在这种情况下索引有很多帮助)或在GHCi中使用:info,你会发现Parser只是意味着......

type Parser = Parsec String ()

...而Parsec又是......

type Parsec s u = ParsecT s u Identity

...以便扩展Parser同义词给出ParsecT String () Identity,这就是GHC在你介绍类型漏洞时告诉你的。