私は現在 Writer モナドについて学んでいますが、do
ブロック内のモナドの値とアキュムレータの両方を読み取ることが正しいかどうかはわかりません。たとえば、以下の coltzSeq 関数では、配列アキュムレータの長さを関数の最終計算として読み取りたいと考えています。これを行うことは可能ですか、またはこれは Writer の不適切な使用ですか? 明らかに、呼び出し元に最終的な配列の長さを読み取らせるか、State モナドを使用することができますが、これは単なる演習です。
module Main where
import Prelude
import Data.Tuple
import Control.Monad.Writer
import Math (remainder, (%))
import Data.Int (toNumber, fromNumber)
import Control.Monad.Eff.Console (logShow)
coltz :: Number -> Number
coltz n = case (n % 2.0 == 0.0) of
true -> n / 2.0
false -> 3.0 * n + 1.0
coltzW :: Number -> Writer (Array Number) Number
coltzW n = do
tell [n]
pure $ coltz n
-- Computes a coltz sequence and counts how many
-- steps it took to compute
coltzSeq :: Number -> Writer (Array Number) Int
coltzSeq n = do
-- Can read the value in the writer
-- but not the writer's internal state
v <- (coltzW n)
let l = 1
-- Can read the value and the internal
-- state, but it's not bound to the monad's context.
-- let a = runWriter (coltzW n)
-- let v = fst a
-- let l = length (snd a)
case (v) of
1.0 -> pure $ l
_ -> to1 v
編集: gb. の提案を試し、listens
type を持つ関数を使用してみました(Monoid w, Monad m) => forall w m a b. MonadWriter w m => (w -> b) -> m a -> m (Tuple a b)
。id
このコンテキストで使用すると、型は次のようになります...
MonadWriter w m => (w -> b) -> m a -> m (Tuple a b)
w = Array Number
m = WriterT (Array Number) Identity (alias: Writer (Array Number) )
b = Array Number
a = Number
(Array Number -> Array Number) ->
Writer (Array Number) Number ->
Writer (Array Number) (Tuple Number (Array Number))
したがって、listens id
を受け入れWriter (Array Number) Number)
、値が現在の Writer 状態である Writer を返します ( を使用したためid
)。ただし、試して使用するすべての方法で型エラーが発生し続けますlistens
to1 :: Number -> (Writer (Array Number)) Int
to1 n = do
v <- (coltzW n)
-- a <- snd <$> listens id
-- let l = snd <$> (listens id (execWriter (coltzW n)))
-- let l = execWriter (listens id (coltzW n))
-- Seems like this one should work to get Array Number
-- let l = snd <$> (listens id (coltzW n))
case (v) of
1.0 -> pure 1
_ -> to1 v
Edit2: 何をする必要があるかを理解しました。何らかの理由で、使用時に型注釈を追加する必要がありましたlistens
。
lengthOfSeq :: Writer (Array Number) Int -> Writer (Array Number) Int
lengthOfSeq c = do
-- Without type annotation, I get this error...
-- No type class instance was found for
--
-- Control.Monad.Writer.Class.MonadWriter (Array t0)
-- (WriterT (Array Number) Identity)
--
-- The instance head contains unknown type variables. Consider adding a type annotation.
Tuple a w <- (listens id c :: Writer (Array Number) (Tuple Int (Array Number)))
pure $ length w
to1 :: Number -> (Writer (Array Number)) Int
to1 n = lengthOfSeq $ seq n
where
seq n = do
v <- coltzW n
case (v) of
1.0 -> do
pure 1
_ -> seq v