হাসকেলে নেস্টেড স্টেটস


9

আমি কিছুটা বিভিন্ন ধরণের রাজ্য সহ রাষ্ট্রীয় মেশিনগুলির একটি পরিবারকে সংজ্ঞায়িত করার চেষ্টা করছি। বিশেষত, আরও "জটিল" রাষ্ট্রীয় মেশিনগুলিতে এমন রাজ্য রয়েছে যা সরল রাষ্ট্র মেশিনগুলির রাজ্যগুলিকে একত্রিত করে গঠিত হয়।

(এটি কোনও অবজেক্ট ওরিয়েন্টেড সেটিংয়ের মতো যেখানে কোনও বস্তুর বিভিন্ন বৈশিষ্ট্য রয়েছে যা বস্তুও।

আমি কী অর্জন করতে চাই তার একটি সরল উদাহরণ এখানে।

data InnerState = MkInnerState { _innerVal :: Int }

data OuterState = MkOuterState { _outerTrigger :: Bool, _inner :: InnerState }

innerStateFoo :: Monad m => StateT InnerState m Int
innerStateFoo = do
  i <- _innerVal <$> get
  put $ MkInnerState (i + 1)
  return i

outerStateFoo :: Monad m =>  StateT OuterState m Int
outerStateFoo = do
  b <- _outerTrigger <$> get
  if b
    then
       undefined
       -- Here I want to "invoke" innerStateFoo
       -- which should work/mutate things
        -- "as expected" without
       -- having to know about the outerState it
       -- is wrapped in
    else
       return 666

আরও সাধারণভাবে, আমি একটি সাধারণ কাঠামো চাই যেখানে এই নীড়গুলি আরও জটিল। এখানে আমি কীভাবে করতে চাই তা জানতে চাই।

class LegalState s

data StateLess

data StateWithTrigger where
  StateWithTrigger :: LegalState s => Bool -- if this trigger is `True`, I want to use
                                   -> s    -- this state machine
                                   -> StateWithTrigger

data CombinedState where
  CombinedState :: LegalState s => [s] -- Here is a list of state machines.
                                -> CombinedState -- The combinedstate state machine runs each of them

instance LegalState StateLess
instance LegalState StateWithTrigger
instance LegalState CombinedState

liftToTrigger :: Monad m, LegalState s => StateT s m o -> StateT StateWithTrigger m o
liftToCombine :: Monad m, LegalState s => [StateT s m o] -> StateT CombinedState m o

প্রসঙ্গে, আমি এই যন্ত্রপাতিটির সাথে এটি অর্জন করতে চাই:

আমি এই জিনিসগুলিকে "স্ট্রিম ট্রান্সফর্মারস" নামে ডিজাইন করতে চাই, যা মূলত রাষ্ট্রীয় কাজ: তারা একটি টোকেন গ্রাস করে, তাদের অভ্যন্তরীণ অবস্থা এবং আউটপুটকে কিছু পরিবর্তিত করে। বিশেষত, আমি স্ট্রিম ট্রান্সফর্মারগুলির একটি শ্রেণিতে আগ্রহী যেখানে আউটপুটটি বুলিয়ান মান; আমরা এই "মনিটর" কল করব।

এখন, আমি এই বিষয়গুলির জন্য কম্বিনেটর ডিজাইনের চেষ্টা করছি। এর মধ্যে কয়েকটি হ'ল:

  • একটি preসমন্বয়কারী। ধরা যাক এটি monমনিটর। তারপরে, pre monএমন কোনও মনিটর যা সর্বদা Falseপ্রথম টোকেন গ্রহণ করার পরে উত্পাদন করে এবং তার আচরণের নকল করে monযেন আগের টোকেনটি এখন sertedোকানো হচ্ছে। আমি উপরের উদাহরণের pre monসাথে রাজ্যের মডেল করতে চাই StateWithTriggerযেহেতু নতুন রাষ্ট্র মূল রাষ্ট্রের সাথে বুলিয়ান।
  • একটি andসমন্বয়কারী। মনে করুন যে m1এবং m2মনিটর হয়। তারপরে, m1 `and` m2এমন একটি মনিটর যা এম 1 এবং তারপরে এম 2 তে টোকেনটি ফিড করে এবং তারপরে Trueউত্তর দুটিই সত্য বলে প্রমাণিত হয় produces উভয় মনিটরের রাজ্য বজায় রাখতে হবে বলে আমি উপরের উদাহরণের m1 `and` m2সাথে রাজ্যের মডেল করতে চাই CombinedState

এফওয়াইআই, _innerVal <$> getঠিক gets _innerVal(যেমন gets f == liftM f get, এবং liftMকেবল fmapমনদেদের কাছে বিশেষায়িত)।
চ্যানার

আপনি যেখানে StateT InnerState m Intপ্রথম স্থানে একটি মান পাচ্ছেন outerStateFoo?
চ্যানার

6
আপনি লেন্স দিয়ে আরামদায়ক? এই ব্যবহারের ক্ষেত্রে মনে হয় ঠিক কী zoom
কার্ল

1
@ কার্ল আমি কিছু লেন্স দেখেছি তবে সেগুলি খুব ভাল বুঝতে পারছি না। জুমটি কীভাবে ব্যবহার করবেন সে সম্পর্কে আপনি একটি উত্তরে ব্যাখ্যা করতে পারেন?
অগ্নিশোম চট্টোপাধ্যায়

5
একটি পর্যবেক্ষণ: এই এন্ট্রিটিতে একটি প্রশ্নই নেই।
সাইমন শাইন

উত্তর:


4

আপনার প্রথম প্রশ্নের জন্য, যেমন কার্ল উল্লেখ করেছেন, zoomসেখান থেকে lensআপনি যা চান ঠিক তা করেন। লেন্স সহ আপনার কোডটি এভাবে লেখা যেতে পারে:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens
import Control.Monad.State.Lazy

newtype InnerState = MkInnerState { _innerVal :: Int }
  deriving (Eq, Ord, Read, Show)

data OuterState = MkOuterState
  { _outerTrigger :: Bool
  , _inner        :: InnerState
  } deriving (Eq, Ord, Read, Show)

makeLenses ''InnerState
makeLenses ''OuterState

innerStateFoo :: Monad m => StateT InnerState m Int
innerStateFoo = do
  i <- gets _innerVal
  put $ MkInnerState (i + 1)
  return i

outerStateFoo :: Monad m =>  StateT OuterState m Int
outerStateFoo = do
  b <- gets _outerTrigger
  if b
    then zoom inner $ innerStateFoo
    else pure 666

সম্পাদনা করুন: আমরা যখন এদিকে রয়েছি, আপনি যদি ইতিমধ্যে আনয়ন করেন lensতবে এ জাতীয় innerStateFooলেখা যেতে পারে:

innerStateFoo :: Monad m => StateT InnerState m Int
innerStateFoo = innerVal <<+= 1

5

প্রসঙ্গে, আমি এই যন্ত্রপাতিটির সাথে এটি অর্জন করতে চাই:

আমি এই জিনিসগুলিকে "স্ট্রিম ট্রান্সফর্মারস" নামে ডিজাইন করতে চাই, যা মূলত রাষ্ট্রীয় কাজ: তারা একটি টোকেন গ্রাস করে, তাদের অভ্যন্তরীণ অবস্থা এবং আউটপুটকে কিছু পরিবর্তিত করে। বিশেষত, আমি স্ট্রিম ট্রান্সফর্মারগুলির একটি শ্রেণিতে আগ্রহী যেখানে আউটপুটটি বুলিয়ান মান; আমরা এই "মনিটর" কল করব।

আমি মনে করি আপনি যা অর্জন করতে চান তার খুব বেশি যন্ত্রপাতি দরকার নেই।

newtype StreamTransformer input output = StreamTransformer
  { runStreamTransformer :: input -> (output, StreamTransformer input output)
  }

type Monitor input = StreamTransformer input Bool

pre :: Monitor input -> Monitor input
pre st = StreamTransformer $ \i ->
  -- NB: the first output of the stream transformer vanishes.
  -- Is that OK? Maybe this representation doesn't fit the spec?
  let (_, st') = runStreamTransformer st i
  in  (False, st')

and :: Monitor input -> Monitor input -> Monitor input
and left right = StreamTransformer $ \i ->
  let (bleft,  mleft)  = runStreamTransformer left  i
      (bright, mright) = runStreamTransformer right i
  in  (bleft && bright, mleft `and` mright)

এই StreamTransformerনয় অগত্যা stateful কিন্তু stateful বেশী স্বীকার করে। এগুলির (বা সত্যই কখনও! :) সংজ্ঞায়িত করার জন্য টাইপক্লাসে পৌঁছানোর দরকার নেই (এবং আইএমও করা উচিত নয়!

notStateful :: StreamTransformer input ()
notStateful = StreamTransformer $ \_ -> ((), notStateful)

stateful :: s -> (input -> s -> (output, s)) -> StreamTransformer input output
stateful s k = StreamTransformer $ \input ->
  let (output, s') = k input s
  in  (output, stateful s' k)

alternateBool :: Monitor anything
alternateBool = stateful True $ \_ s -> (s, not s)

এটি খুব দুর্দান্ত, ধন্যবাদ! এই প্যাটার্নটি কি কিছু বলা হয়?
অগ্নিশম চট্টোপাধ্যায়

3
আমি একে খাঁটি ফাংশনাল প্রোগ্রামিং বলব! তবে আমি জানি যে এটি আপনি যে উত্তরটি সন্ধান করছেন তা নয় :) স্ট্রিমিট ট্রান্সফর্মার আসলে একটি " মিলি
আলেকজান্ডার

না, প্রথম আউটপুটটি বিলুপ্ত হওয়া আমার ইচ্ছা মতো নয়। আমি প্রথম আউটপুটটি দ্বিতীয় হতে বিলম্ব করতে চাই ।
অগ্নিশম চট্টোপাধ্যায়

2
এবং তাই, যাতে প্রতিটি আউটপুট এক ধাপে দেরী হয়? এটা করা যেতে পারে।
আলেকজান্ডার ভিয়েহ

1
খুব সুন্দর, পোস্ট করার জন্য ধন্যবাদ! (প্রশ্নটি সঠিকভাবে না পড়ে আগে মন্তব্য করার জন্য দুঃখিত) আমি মনে করি ওপি বলতে বোঝায় pre st = stateful (Nothing, st) k where k i (s,st) = let (o, st') = runStreamTransformer st i in ( maybe False id s , (Just o, st'))
নেস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.