4

私はParsecで遊んでおり、2つのパーサーを1つに結合して、結果をペアにした後、別の関数をフィードして、解析結果を操作し、次のように記述します。

try (pFactor <&> (char '*' *> pTerm) `using` (*))

だから私はこれを書いた:

(<&>) :: (Monad m) => m a -> m b -> m (a, b)
pa <&> pb = do
  a <- pa
  b <- pb
  return (a, b)

using :: (Functor f) => f (a, b) -> (a -> b -> c) -> f c
p `using` f = (uncurry f) <$> p

どこかに実装されている(<&>)に似たものはありますか?それとも、これはポイントフリーで書くことができますか?試してみfmap (,)ましたが、タイプに合わせるのが難しいようです。

4

5 に答える 5

11

より良い、<&>またはliftM2なるだろう

(,) <$> a <*> b

Applicative スタイルは人気が高まっているようで、非常に簡潔です。このようなものに applicative スタイルを使用すると<&>、 よりもはるかに明確になるため、それ自体の必要性がなくなり(,) <$> a <*> bます。

また、これはモナドさえも必要としません - Applicatives でも​​機能します。

于 2011-09-24T20:13:37.890 に答える
7

どこかに実装されている (<&>) に似たものはありますか? それとも、これは無意味に書くことができますか? fmap(,) を試してみたのですが、型を合わせるのが難しそうです。

どこかに実装されているかどうかはわかりません<&>が、 と同じである必要がありますliftM2 (,)。との違いfmapは、二項関数をモナドにliftM2持ち上げることです。

于 2011-09-24T20:10:05.093 に答える
6

Applicative スタイルを使用すると、カリー化されていない関数をすぐに適用するためだけに、中間結果をタプルに入れる必要はありません。<$>と を使用して関数を「直接」適用するだけ<*>です。

try ((*) <$> pFactor <*> (char '*' *> pTerm))

一般に、 と の正常なインスタンスを仮定するMonadApplicative

do x0 <- m0
   x1 <- m1
   ...
   return $ f x0 x1 ...

と同等です

f <$> m0 <*> m1 <*> ...

ただし、後者の形式はより一般的であり、Applicativeインスタンスのみを必要とします。(言語はこれを強制しませんが、すべてのモナドはアプリカティブ ファンクターであるべきです)。

于 2011-09-24T20:20:46.353 に答える
3

反対方向に進むと、パーサーを結合する方法がArrowパラダイムとArrow パーサーの実装Applicativeにうまく適合することがわかることに注意してください。例えば:

import Control.Arrow

(<&>) = (&&&) 

p `using` f = p >>^ uncurry f 
于 2011-09-25T05:25:30.267 に答える
1

はい、適用可能なスタイルを使用できますが、それがあなたの質問のいずれにも答えるとは思いません。

2 つの任意のモナドを取り、それらの値の型をペアに固定し、そのペアをコンテキストに固定する、既に定義されたコンビネーターはありますか?

標準パッケージには含まれていません。

最後のビットポイントを無料でできますか?

アリティが 1 ポイントを超えるカリー化された関数を無料にする方法があるかどうかはわかりません。ないと思います。

それがあなたの質問に答えることを願っています。

于 2011-09-24T20:38:05.907 に答える