2

ブーメランを適切に使用して URL を生成する方法について、私は少し混乱しています。私は次のものを持っています:

data State =
  AK | AL | AR | AZ | CA ... WY

data Sitemap
    = Home
    | State State
    | Place State String
      deriving (Eq, Ord, Read, Show, Data, Typeable)

$(derivePrinterParsers ''Sitemap)

sitemap ∷ Router Sitemap
sitemap =
    (  rHome
    <> rState . state
    <> rPlace . (state </> anyString)
    )

state :: PrinterParser StringsError [String] o (State :- o)
state = xmaph read (Just . show) anyString

stateこれは機能しているように見えますが、 の実装と のドキュメントの実装を比較するとarticleId、反対の方法で動作しているように見えます。

articleId :: Router ArticleId
articleId = xmaph ArticleId (Just . unArticleId) int

タイプはまったく異なり、逆方向に進んでいるように見えますが、私のsitemap作品とアプリは正しく URL を処理します。私はそれがもっとこのように見えるべきだと思います:

maybeState :: String → Maybe State
maybeState stateString = case reads stateString of
                     [(state, "")] -> Just state
                     _             -> Nothing

stateR :: Router State
stateR = xpure show maybeState

これは型チェックを行いませんが、上記のundefined定義を置き換えても機能しますが、機能しません。sitemaprState . stateRrPlace . (stateR </> anyString)

おそらくこれを処理するライブラリ関数があるので、これは十分に頻繁に発生するようですが、私はそれを見ませんでした。

編集:ここに私が得る型エラーのいくつかがあります:

の場合state = xpure show maybeState:

Main.hs:56:16:
    Couldn't match expected type `State :- ()'
                with actual type `[Char]'
    Expected type: () -> State :- ()
      Actual type: () -> String
    In the first argument of `xpure', namely `show'
    In the expression: xpure show maybeState

For state = undefined :: Router State(このエラーはsitemap定義にあります):

Main.hs:45:18:
    Couldn't match expected type `String :- ()' with actual type `()'
    Expected type: PrinterParser
                     StringsError [String] () (State :- (String :- ()))
      Actual type: Router State
    In the first argument of `(</>)', namely `state'
    In the second argument of `(.)', namely `(state </> anyString)'
4

1 に答える 1

1

行で状態を使用するには、型エイリアスで許可されrPlaceているよりも一般的な型シグネチャが必要であるため、型が異なって見えます。Router(あなたのコードは問題ありません。しかし、ブーメランでより一般的なエイリアスを提供する必要があるかもしれません..)

rPlace 行を削除すると、state の型シグネチャを次のように変更できます。

state :: Router State
state = xmaph read (Just . show) anyString

もっとよく見るとstatearticleId実際に同じ方向に進んでいることがわかると思います。

articleId :: Router ArticleId
articleId = xmaph ArticleId (Just . unArticleId) int

の 3 番目の引数は、xmaph基になる値を解析する方法を指定します。の場合articleIdは an を解析しint、 forのstate場合は を解析しanyStringます。

の最初の引数はxmaph、その値を目的の戻り値の型に変換する方法を指定します。コンストラクターarticleIdを単純に適用します。ArticleIdで関数stateを適用しreadます。ただし、どちらの場合も、基になる値から目的の戻り値の型に移行します。

ArticleId :: Int    -> ArticleId
read      :: String -> State

の 2 番目の引数xmaphは、戻り値の型を元の値に変換する方法を指定します。

show        :: State     -> String
unArticleId :: ArticleId -> Int

とはいえ、「読み取り」は失敗してエラーになる可能性があるため、ここで実際に「読み取り」を使用するべきではありません。xmaph の最初の引数が合計関数になることを意図しています。

Stringsという名前のモジュールに新しいコンビネータを追加するブーメラン 1.3.1 をアップロードしましたreadshow。この関数は、Read インスタンスと Show インスタンスを正しく使用します。残念ながら、エラー報告は少しずさんです。なぜなら、reads失敗したときに、失敗した理由や場所について何も教えてくれないからです。しかし、それは何もないよりはましです:)

それを使用して、次のように記述できます。

state :: PrinterParser StringsError [String] o (State :- o)
state = readshow

無効な状態を指定すると、次のようになります。

> parseStrings sitemap ["AZ"]
Right (State AZ)
> parseStrings sitemap ["FOEU"]
Left parse error at (0, 0): unexpected FOEU; decoding using 'read' failed.
于 2012-03-14T20:25:28.083 に答える