重构 where 子句
Refactoring where clause
我正在学习 Haskell,所以这可能是一些非常琐碎的事情,但我希望能得到一些关于如何重写它以及它如何工作的指示。
我有以下工作代码(使用的包:HTF, Parsec and Flow):
{-# 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 ", ....]
我仍然不确定那些 monad,但我以某种方式让它工作(那些 _
aka 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)
但我不得不猜测 Parser 类型,漏洞给我带来了非常复杂的东西 - Text.Parsec.Prim.ParsecT s () Data.Functor.Identity.Identity a -> [s -> IO ()]
。
如您所见,问题出在 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 ()
positive
和 negative
是已经具有要传递给 mapM
的适当类型的函数,因此如果您希望 pos_neg_case
将它们作为列表返回除了包装在列表中之外,您不需要做任何事情。 return
不是关键字;它只是一个将值注入 monadic 上下文的函数。如果您不需要进行任何此类注入,则不需要 return
.
P.S.: 引用你的回答:
But I had to guess the Parser type, hole was giving me very complex thingy
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 在您引入类型孔时告诉您的内容。
我正在学习 Haskell,所以这可能是一些非常琐碎的事情,但我希望能得到一些关于如何重写它以及它如何工作的指示。
我有以下工作代码(使用的包:HTF, Parsec and Flow):
{-# 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 ", ....]
我仍然不确定那些 monad,但我以某种方式让它工作(那些 _
aka 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)
但我不得不猜测 Parser 类型,漏洞给我带来了非常复杂的东西 - Text.Parsec.Prim.ParsecT s () Data.Functor.Identity.Identity a -> [s -> IO ()]
。
如您所见,问题出在 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 ()
positive
和 negative
是已经具有要传递给 mapM
的适当类型的函数,因此如果您希望 pos_neg_case
将它们作为列表返回除了包装在列表中之外,您不需要做任何事情。 return
不是关键字;它只是一个将值注入 monadic 上下文的函数。如果您不需要进行任何此类注入,则不需要 return
.
P.S.: 引用你的回答:
But I had to guess the Parser type, hole was giving me very complex thingy
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 在您引入类型孔时告诉您的内容。