2014-11-19 16 views
5

Tôi có một hàm đơn giản sử dụng Control.Monad.Random để tạo một hàm có thể lấy mẫu một số ngẫu nhiên.Kết hợp RandT và MaybeT

import Control.Monad.Random  
import Data.Random   

unif_bound :: (RandomGen g, Monad m) => Double -> Double -> RandT g m Double 
unif_bound lb ub = getRandomR (lb,ub) 

Và, tôi chạy này để tạo số ngẫu nhiên trong GHCI như:

> gen <- newStdGen 
    > runRandT (unif_bound 1.0 3.0) gen 
(1.7569726469904563,1700403094 44073136) 
    > runRandT (unif_bound 3.0, 1.0) gen 
(1.7569726469904563,1700403094 44073136) 

Tuy nhiên, tôi muốn thay đổi mã này để kiểm tra xem lb < ub, và bọc này trong một MaybeT. Ý tưởng là lấy mẫu nơi lb > ub phải trả lại Nothing. Tôi nhận ra rằng đây là nơi mà các biến thế đơn nguyên xuất hiện, nhưng tôi chưa bao giờ sử dụng một cái trước và không chắc chắn nên bắt đầu từ đâu.

Để tham khảo, RandT được định nghĩa là

-- | A monad transformer which adds a random number generator to an 
-- existing monad. 
newtype RandT g m a = RandT (StateT g m a) 
    deriving (Functor, Monad, MonadTrans, MonadIO, MonadFix, MonadReader r, MonadWriter w) 

Cảm ơn!

+1

http://en.wikibooks.org/wiki/Haskell/Monad_transformers. Bạn cũng có thể chỉ cần trả lại một 'RandT g m (Có thể đôi)' - máy biến áp đôi khi quá mức cần thiết, và âm thanh như họ có thể là dành cho trường hợp của bạn. Nhưng một cơ hội tốt để học hỏi! – luqui

Trả lời

1

Bạn có thể khái quát các loại hình chức năng của bạn khá một chút:

unif_bound :: (Random a, Ord a, MonadRandom m) => a -> a -> MaybeT m a 
unif_bound lb ub | lb > ub = MaybeT (return Nothing) 
       | otherwise = getRandomR (lb,ub) 

Lưu ý rằng bạn có thể thay thế MaybeT (return Nothing) với fail "" vì đó là cách thất bại được định nghĩa trong trường hợp đơn nguyên cho MaybeT m, nhưng đây không phải là rất đẹp. Cách sử dụng:

>runMaybeT $ unif_bound 1 10 
Just 2 
>runMaybeT $ unif_bound 400 1 
Nothing 

IO là một thể hiện của MonadRandom, do đó bạn không cần phải fiddle với RandT nếu bạn đang chỉ là thử nghiệm trong phiên dịch.