2

1) フィールド コンストラクター パラメーターを関数に渡す必要があります。いくつかのテストを行いましたが、できませんでした。出来ますか?もしくはレンズパッケージで可能でしょうか?

2) MonadState で変更を使用してフィールドを変更することは可能ですか? (私はいくつかの試みをしましたが、成功しませんでした。たとえば、modify (second = "x") は機能しません。

import Control.Monad.State

data Test = Test {first :: Int, second :: String} deriving Show

dataTest = Test  {first = 1, second = ""}

test1 = runStateT modif1 dataTest -- OK

test2 = runStateT (modif2 "!") dataTest -- OK

test3 = runStateT (modif3 second) dataTest -- WRONG


-- modif1 :: StateT Test IO ()
modif1 = do
  st <- get
  r <- lift getLine
  put $ st {second = "x" ++ r} 


-- modif2 :: String -> StateT Test IO ()
modif2 s = do
  stat <- get
  r <- lift getLine
  put $  stat {second = "x" ++ r ++ s}

-- modif3 :: ???? -> StateT Test IO ()
modif3 fc = do
  stat <- get
  r <- lift getLine
  put $  stat {fc = "x" ++ r}

-- When i try to load the module, this is the result:
-- ghc > Failed:
--  ProvaRecord.hs:33:16:`fc' is not a (visible) constructor field name
4

1 に答える 1

5

おっしゃるとおり、レンズを探しているのでしょう。レンズは、特定のフィールドの読み取り、設定、または変更を可能にする値です。通常、Control.Lensではアンダースコアでフィールドを定義し、 を使用makeLensesしてフル機能のレンズを作成します。

内でレンズを一緒に使用できるようにする多くのコンビネータがありますMonadState。あなたの場合、 を使用できます%=。この場合、これは型に特化されます

(MonadState s m) => Lens' s b -> (b -> b) -> m ()

これは、与えられたレンズと内側の値に作用する関数を使用して状態値を変更します。

あなたの例は、レンズを使用して次のように書き直すことができます。

{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
import Control.Monad.State

data Test = Test { _first :: Int
                 , _second :: String
                 }
    deriving Show

-- Generate `first` and `second` lenses.
$(makeLenses ''Test)

-- | An example of a universal function that modifies any lens.
-- It reads a string and appends it to the existing value.
modif :: Lens' a String -> StateT a IO ()
modif l = do
    r <- lift getLine
    l %= (++ r)


dataTest :: Test
dataTest = Test  { _first = 1, _second = "" }

test :: IO Test
test = execStateT (modif second) dataTest
于 2014-05-01T07:38:31.230 に答える