2016-11-06 15 views
3

私はハスケルを学んでいるので、それはおそらくかなり些細なことですが、書き直しの仕方や使い方についてのいくつかの指摘に感謝します。リファクタリングwhere節

私は、作業コード(使用パッケージ: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)からのものです。(/>)は、[* flow *](https://hackage.haskell.org/package/flow-1.0.7/docs/Flow)からのものです。 .html)、 'flip($)'と '(&)'と同義語です。 (あまり知られていない、あなたが使用しているパッケージには、より明確な質問があります) – duplode

+0

@duplodeああ、ありがとうございます(輸入が十分であると思いました)。私はフロー*がハスケラーの間であまり人気がないことを知っていましたが、* 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同義語を拡大するようにすることで、型穴を導入したときにGHCがあなたに言ったことである、ParsecT String() Identityを与えます。

+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()]を。