2017-12-05 7 views
5

ハローフェローハスケラー。アプリケーションファンクタを複数回適用する方法

私は、適用可能なファンクタ(モナドのインスタンスではない)を持っているとしましょう。 純粋な初期値に複数回適用したいとします。私は連続し 任意の数のアプリケーションにこれを一般化したい場合例えば、

λ> Just (1+) <*> (Just (1+) <*> pure 0) 
Just 2 

は、私はfoldでそれを行うことができます。この定義の後

applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a 
applyAppl f n i = foldr (<*>) i $ replicate n f 

λ> applyAppl (Just (1+)) 10 $ pure 0 
Just 10 

私は一般化も は、sequenceAtraverseなどの高次組み込み応用的なツールの一つで行うことができるという厄介な疑いを持っています。それをできる?

(最初の2つのコメントの下に考慮に入れるように編集。)

+2

書き込みしようとしている関数のタイプを教えてください。 –

+0

「もっと簡単に」とはどういう意味ですか?あなたの関数は1行のコードです。それよりもはるかに簡単にはなりません。 – user2407038

+0

あなたは何をしたいですか?私は何かを考えようとしましたが、実際に何らかの折り畳みに終わりました。そして、あなたは関数をアプリケーションから取り出してhaskの関数にするために '<*>'を呼び出さなければなりません。 – HuStmpHrrr

答えて

3

あなたはiterateを使用することができます。

GHCiのにロードされた
applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a 
applyAppl f n i = iterate (f <*>) i !! n 

ghci> applyAppl (Just (+1)) 10 (pure 0) 
Just 10 

私は確信してのことではありませんよ私は両方の実装が本質的に同じ性能プロファイル(何かをテストしていないが)に融合していると思うので、実装よりも必ずしも優れているが、それは異なっている。

私はこの種の "iterate with (!!)"のメモ帳のパターンを見てきましたので、少なくとも、それはパフォーマンスが悪くないことは間違いありません。

+0

すでに改良が施されていますが、 '(<*>)'を明示的に指定する必要があります。この場合は 'iterate'に明示的に指定する必要があります。適用機械がこの問題を直接解決するためにどのように使用できるかを理解しようとしています。 – jhu

+0

@jhuそれを避けるためのものは何もないと確信しています。私は間違っている可能性があります(特に2時35分、hahです)。しかし、今は何も考えられません。私が考えることができる組み込みのアプリケーション機能のうち、どれも「ステートフル」(必要な方法で)必要なものはありません。どのような方法でも中間結果を把握していません。たとえば、 '(sequence(fmap sequence(replicateM 10(Just(+1)))))0'のようなものは' Just [1,1,1,1,1,1,1,1] 、1,1]。 –

0

おそらく、あなたは@デビッドヤング答え、次の変化を探しています:

foo :: Applicative f => f (a -> a) -> Int -> a -> f a 
foo f n i = fmap (($ i) . iterateN n) f 
    where iterateN n f = (!! n) . iterate f 

与える:

> foo (Just (1+)) 10 0 
Just 10 
> 

をこれはapplicativesためのFunctorインスタンスの形で「応用的機械」を使用しています<*>を明示的に使用することなく、関数の反復とアプリケーションの両方を実行できます。私はあなたがここで何を望んでいるかわからない。

関連する問題