隐藏状态monad的类型参数

时间:2015-12-17 05:38:22

标签: haskell existential-type gadt

我正在尝试在新类型中隐藏State monad的类型参数,但我很难将存在限定的sg统一到为evalFoo提供。我尝试过使用ExistentialQuantificationGADTsRankNTypes,但对这些扩展的工作原理一无所知。

惯用的Haskell如何实现这种外观? 谢谢!

{-# LANGUAGE GADTs #-}

import Control.Monad.State
import System.Random

data Foo a where
  Foo :: RandomGen s => State s a -> Foo a

evalFoo :: RandomGen g => Foo a -> g -> a
evalFoo (Foo m) g = evalState m g

目标是实现这样的目标,但能够提供RandomGen的任何实例:

myRNG :: Foo Double
myRNG = Foo $ do
  u <- state random
  return u

Prelude> evalFoo myRNG (mkStdGen 123)
0.7804356004944119

2 个答案:

答案 0 :(得分:6)

Foo构造函数类型中的存在量化意味着对于Foo类型的每个值,都会将RandomGen的某个实例用作其状态。但是,您希望相反:您想要foo :: Foo的任何值g以及RandomGen的任何实例g,您可以使用foo作为{-# LANGUAGE Rank2Types #-} import Control.Monad.State import System.Random newtype Foo a = MkFoo{ unFoo :: forall g. (RandomGen g) => State g a } evalFoo :: RandomGen g => Foo a -> g -> a evalFoo = evalState . unFoo myRNG :: Foo Double myRNG = MkFoo $ do u <- state random return u 封装的计算状态。

所以让我们写一下:

*Main> evalFoo myRNG (mkStdGen 123)
0.43927189736460226

这可以按预期使用:

if(isset($_POST["btnImport"]))
                 {
                      $uploads_dir = 'C:/wamp/www/quiz admin/uploads';
                      $tmp_name = $_FILES["excelFile"]["tmp_name"];
                      $name = $_FILES["excelFile"]["name"];
                    if(!empty($_FILES["excelFile"]["tmp_name"]))
                     {
                        move_uploaded_file($tmp_name, "$uploads_dir/$name");
                        $fileupload = $_FILES["excelFile"]["tmp_name"];                          
                        $fileName = explode(".",$_FILES["excelFile"]["name"]);
                        if($fileName[1]=="xls"||$fileName[1]=="xlsx")
                        {
                   $data = new Spreadsheet_Excel_Reader($uploads_dir.'/'.$name);

df.index.isin(sample)

是的,不是0.78;)

答案 1 :(得分:4)

这个问题就像你描述的那样。您将无法将存在包裹的随机种子与您的初始随机种子统一起来。最明显的方法是完全放弃存在量化,并使用它:

runRandomly :: RandomGen g => State g a -> g -> a
runRandomly (Foo m) g = evalState m g

在这种情况下,我认为最明显的方法没有任何问题。如果您真的想要隐藏变换器中的种子类型,Cactus's answer会显示如何正确执行此操作。

在其他一些情况下,一些类似的存在包装可以通过将种子与变换器一起包装来实现:

data Foo a where
  Foo :: RandomGen s => State s a -> s -> Foo a

您可以在foldl包中看到类似内容的示例。