হসকেলে কন্ট্রোল.মোনাদ.উইটারের সাথে কীভাবে খেলবেন?


97

আমি কার্যনির্বাহী প্রোগ্রামিংয়ে নতুন এবং সম্প্রতি শিখুন আপনি একটি হাস্কেল- এ শিখছি , কিন্তু যখন আমি এই অধ্যায়ের মধ্য দিয়ে গেলাম, তখন আমি নীচের প্রোগ্রামটির সাথে আটকে গেলাম:

import Control.Monad.Writer  

logNumber :: Int -> Writer [String] Int  
logNumber x = Writer (x, ["Got number: " ++ show x])  

multWithLog :: Writer [String] Int  
multWithLog = do  
    a <- logNumber 3  
    b <- logNumber 5  
    return (a*b)

আমি এই রেখাগুলি একটি .hss ফাইলে সংরক্ষণ করেছিলাম এবং এটি আমার জিএসিচিতে আমদানি করতে ব্যর্থ হয়েছি যা অভিযোগ করেছে:

more1.hs:4:15:
    Not in scope: data constructor `Writer'
    Perhaps you meant `WriterT' (imported from Control.Monad.Writer)
Failed, modules loaded: none.

আমি ": তথ্য" কমান্ড দ্বারা প্রকারটি পরীক্ষা করেছি:

Prelude Control.Monad.Writer> :info Writer
type Writer w = WriterT w Data.Functor.Identity.Identity
               -- Defined in `Control.Monad.Trans.Writer.Lazy'

আমার দৃষ্টিকোণ থেকে, এটি "নিউ টাইপ রাইটার ওয়া ..." এর মতো কিছু হওয়ার কথা ছিল তাই ডেটা কনস্ট্রাক্টরকে কীভাবে খাওয়ানো যায় এবং একজন রাইটার কীভাবে পাওয়া যায় সে সম্পর্কে আমি বিভ্রান্ত।

আমার ধারণা এটি কোনও সংস্করণ সম্পর্কিত সমস্যা হতে পারে এবং আমার জিএইচসি সংস্করণটি 7.4.1


4
অনুশীলনের জন্য, আমি ঘোষণাটি আমদানি না করে এবং এটি ফাইলটিতে নিজের লেখা না করার পরামর্শ দিচ্ছি।
sdcvvc

4
আমি লেখকটির সাথে কিছুক্ষণ আগে কথা বলেছি এবং তিনি নিশ্চিত করেছেন যে বইটির অনলাইন সংস্করণটি পুরানো। পিডিএফে আরও একটি আপ-টু-ডেট সংস্করণ রয়েছে: [এখানে ]
বৈদ্যুতিন কফি

@ ইলেক্ট্রিক, আমার একই প্রশ্ন, আপনি দয়া করে একটি লিঙ্ক দিতে পারেন? আপনার উপরের লিঙ্কটি নষ্ট হয়ে গেছে।
বুলাত এম।

উত্তর:


127

প্যাকেজটি Control.Monad.Writerডেটা কনস্ট্রাক্টর রফতানি করে না Writer। আমার ধারণা, লায়াহ লেখা হয়েছিল যখন এটি আলাদা ছিল।

GCI এ MonadWriter টাইপক্লাস ব্যবহার করে

পরিবর্তে, আপনি writerফাংশনটি ব্যবহার করে লেখক তৈরি করেন । উদাহরণস্বরূপ, একটি ঘিসি অধিবেশনে আমি করতে পারি

ghci> import Control.Monad.Writer
ghci> let logNumber x = writer (x, ["Got number: " ++ show x])

এখন logNumberএকটি ফাংশন যা লেখক তৈরি করে। আমি এর ধরণের জন্য জিজ্ঞাসা করতে পারি:

ghci> :t logNumber
logNumber :: (Show a, MonadWriter [String] m) => a -> m a

যা আমাকে জানিয়েছে যে অনুমিত টাইপ কোনও ফাংশন নয় যা কোনও নির্দিষ্ট লেখককে ফিরিয়ে দেয় , বরং এমন কোনও কিছু যা MonadWriterপ্রকারের শ্রেণিকে প্রয়োগ করে । আমি এখন এটি ব্যবহার করতে পারি:

ghci> let multWithLog = do { a <- logNumber 3; b <- logNumber 5; return (a*b) }
    :: Writer [String] Int

(ইনপুট আসলে এক লাইনে সমস্ত প্রবেশ করিয়েছে)। এখানে আমি প্রকার নির্দিষ্ট করে থাকেন multWithLogহতে Writer [String] Int। এখন আমি এটি চালাতে পারি:

ghci> runWriter multWithLog
(15, ["Got number: 3","Got number: 5"])

এবং আপনি দেখতে পান যে আমরা মধ্যবর্তী অপারেশনগুলির সমস্ত লগ করছি।

কোডটি এভাবে লেখা হয় কেন?

মোটেই MonadWriterটাইপ ক্লাস তৈরি করতে বিরক্ত করবেন কেন ? কারণটি হ'ল মোনাড ট্রান্সফর্মারগুলি দিয়ে। আপনি যেমনটি সঠিকভাবে উপলব্ধি করেছেন, বাস্তবায়নের সহজতম উপায় Writerহ'ল একটি জোড়ার শীর্ষে একটি নতুন প্রকারের মোড়ক:

newtype Writer w a = Writer { runWriter :: (a,w) }

আপনি এটির জন্য একটি মোনাড উদাহরণ ঘোষণা করতে পারেন এবং তারপরে ফাংশনটি লিখতে পারেন

tell :: Monoid w => w -> Writer w ()

যা কেবল তার ইনপুট লগ করে। এখন ধরা যাক আপনি এমন একটি মোনাড চান যাতে লগিংয়ের ক্ষমতা রয়েছে তবে অন্য কিছু করে - বলুন এটি পরিবেশ থেকেও পড়তে পারে। আপনি এটি হিসাবে বাস্তবায়ন চাই

type RW r w a = ReaderT r (Writer w a)

এখন লেখক ReaderTমোনাড ট্রান্সফর্মারের ভিতরে রয়েছে , আপনি যদি আউটপুট লগ করতে চান তবে আপনি ব্যবহার করতে পারবেন না tell w(কারণ এটি কেবল মোড়কানো লেখকদের সাথে কাজ করে) তবে আপনাকে ব্যবহার করতে হবে lift $ tell w, যা tellফাংশনটিকে "উত্তোলন" করে ReaderTযাতে এটি অ্যাক্সেস করতে পারে অন্তর্ লেখক মনাদ। আপনি যদি দুটি স্তর ট্রান্সফর্মার চেয়েছিলেন (বলুন যে আপনি ত্রুটি পরিচালনা করার পাশাপাশি যুক্ত করতে চান) তবে আপনাকে ব্যবহারের প্রয়োজন হবেlift $ lift $ tell w । এটি দ্রুত অস্বাস্থ্যকর হয়ে পড়ে।

পরিবর্তে, একটি প্রকার শ্রেণি নির্ধারণ করে আমরা কোনও লেখকের চারপাশে যে কোনও মোনাড ট্রান্সফর্মার মোড়ককে লেখকের নিজের উদাহরণ হিসাবে তৈরি করতে পারি। উদাহরণ স্বরূপ,

instance (Monoid w, MonadWriter w m) => MonadWriter w (ReaderT r m)

এটি হ'ল যদি wএকঘেয়ে হয় এবং mএটি একটি হয় MonadWriter wতবে ReaderT r mএটিও একটি MonadWriter w। এর অর্থ হ'ল আমরা tellফাংশনটি সরাসরি মোনাড ট্রান্সফর্মারের মাধ্যমে এটিকে উত্থাপিত করে বিরক্ত না করেই পরিবর্তিত মনডের উপরে সরাসরি ব্যবহার করতে পারি ।


31
"আমার ধারণা লায়াহ লেখা হয়েছিল যখন এটি আলাদা ছিল।" ঠিক। এটি mtlবড় সংস্করণ ১ থেকে শুরু করে পরিবর্তিত হয়েছিল * চরম দুর্ভাগ্যজনক সময় যা নবীনদের মাঝে অনেক বিভ্রান্তির দিকে পরিচালিত করে এবং নিয়ে যায়।
ড্যানিয়েল ফিশার

4
আমি এখন GHC সংস্করণটি 7.8.3 ব্যবহার করছি এবং আমাকে আমদানি করতে হয়েছিল Control.Monad.Trans.Writer। উপরন্তু ধরণ logNumberহয় logNumber :: (Show a, Monad m) => a -> WriterT [[Char]] m aআমার জন্য।
কিমিকায়েল

@kmikael আপনার কাছে সম্ভবত mtlগ্রন্থাগারটি ইনস্টল করা নেই (যার অর্থ সম্ভবত আপনি হ্যাজকেল প্ল্যাটফর্মের পরিবর্তে minGHC এর মতো জিএইচসি-র একটি বেস ইনস্টলেশন স্থাপন করেছেন)। কমান্ড প্রম্পট রান থেকে cabal updateএবং cabal install mtlতারপর আবার চেষ্টা করুন।
ক্রিস টেলর

ক্রিস, আমি হাস্কেল প্ল্যাটফর্মটি ব্যবহার করছিলাম এবং এমটিএল ইনস্টল করা হয়েছিল, যদিও আমি এটি আবার ইনস্টল করেছি এবং এখন এটি আপনার উত্তরের মতো কাজ করছে বলে মনে হচ্ছে। আমি জানি না ভুল কি ছিল। ধন্যবাদ
কিমিকায়েল

পরিবর্তে বইটির মুদ্রিত অনুলিপিটি সঠিক। এটিতে একটি অনুচ্ছেদে রয়েছে যা ব্যাখ্যা করে যা পরবর্তীকালের পরিবর্তে, মান কর্টার হিসাবে writerব্যবহৃত Writerহয়, মডিউল দ্বারা রফতানি করা হয় না, যদিও পূর্ববর্তীটি হয়, এবং এটি একইভাবে মানটি তৈরি করতে ব্যবহার করা যেতে পারে যা আপনি কর্টারের সাহায্যে তৈরি করেন তবে তা করে প্যাটার্ন মিলের অনুমতি দেয় না।
এনরিকো

8

"লেখক" নামে একটি ফাংশন একটি "লেখক" কনস্ট্রাক্টরের পরিবর্তে উপলব্ধ করা হয়। পরিবর্তন:

logNumber x = Writer (x, ["Got number: " ++ show x])

প্রতি:

logNumber x = writer (x, ["Got number: " ++ show x])


6
এটি বিদ্যমান উত্তরের সাথে কী যুক্ত করে?
dfeuer

1

অনলাইন হাস্কেল সম্পাদককে অনলাইনে ব্যবহার করে লায়াহ "কয়েক মনডের জন্য আরও" চেষ্টা করার অনুরূপ বার্তা পেয়েছি repl.it

আমি এর থেকে আমদানি পরিবর্তন করেছি:

import Control.Monad.Writer

প্রতি:

import qualified Control.Monad.Trans.Writer.Lazy as W

সুতরাং আমার কোডটি এখন এ জাতীয় দেখায় ( কোয়াংয়ের হাস্কেল ব্লগের অনুপ্রেরণা সহ ):

import Data.Monoid
import qualified Control.Monad.Trans.Writer.Lazy as W


output :: String -> W.Writer [String] ()
output x = W.tell [x]


gcd' :: Int -> Int -> W.Writer [String] Int  
gcd' a b  
    | b == 0 = do  
        output ("Finished with " ++ show a)
        return a  
    | otherwise = do  
        output (show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b))
        gcd' b (a `mod` b)

main :: IO()
main = mapM_ putStrLn $ snd $ W.runWriter (gcd' 8 3) 

কোড বর্তমানে এখানে চলমান

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.