在Haskell中展开函数类型

时间:2014-12-03 22:37:22

标签: haskell

有没有办法在Haskell中解包以下类型?

newtype Rand a = Rand(StdGen -> (a , StdGen))

我有一个返回此类型的功能,另一个我想使用' a'返回函数的值,但我无法弄清楚如何提取值。

4 个答案:

答案 0 :(得分:5)

当你写:

newtype Rand a = Rand(StdGen -> (a , StdGen))

了解你正在写什么非常重要。

在这种情况下,newtype相当于data(唯一需要注意的是newtype更有效率)。所以,我们也可以这样编写类型定义:

data Rand a = Rand (StdGen -> (a, StdGen))

一块一块:

Type constructor
      |              ..-- Type parameter
     \|/       ..--''
      '   .--''
data Rand a = Rand (StdGen -> (a, StdGen))
               .   '---------------------'
              /|\              |
               |               '- Wrapped data
     Data constructor

首先,让我们看一个更简单的例子:

data Sum = Sum Int

注释:

Type constructor
      |
     \|/
      '
data Sum = Sum Int
            .  '-'
           /|\  '--- Wrapped data
            |
     Data constructor

为了更清楚,我们将类型(构造函数)与(数据)构造函数区分开来:

data SumType = SumCon Int

现在,我们如何提取值Int中的x :: SumType

显而易见的选择是模式匹配:

getSum :: SumType -> Int
getSum (SumCon n) = n

这很有效。但这是一个非常普遍(而且微不足道)的事情 - 想要做到更容易,并且记录语法'被介绍了。这意味着我们可以像这样重写我们的类型:

data SumType = SumCon { getSum :: Int }

现在我们不再需要手动编写getSum - 编译器会为我们执行此操作,这意味着我们可以假设函数getSum :: SumType -> Int存在。

现在,让我们回到Rand a

newtype Rand a = Rand (StdGen -> (a, StdGen))

我们可以手动写:

getRand :: Rand a -> (StdGen -> (a, StdGen))
getRand (Rand f) = f

或者让编译器为我们做:

newtype Rand a = Rand { getRand :: StdGen -> (a, StdGen) }

答案 1 :(得分:2)

如果您有数据类型

newtype Rand a = Rand (StdGen -> (a, StdGen))

只有a提供StdGen的唯一方法是提供StdGen -> (a, StdGen)(请记住,这或多或少是runRand :: Rand a -> StdGen -> (a, StdGen) runRand (Rand f) g = f g 的别名):

Rand

为了简化,我建议改为使用记录语法定义newtype Rand a = Rand { runRand :: StdGen -> (a, StdGen) }

runRand

a的类型相同,但现在它们都在一行中为您定义。如果您只想要fst值,则只需使用evalRand :: Rand a -> StdGen -> a evalRand r g = fst $ runRand r g

{{1}}

答案 2 :(得分:1)

只需将其命名为记录......

newtype Rand a = Rand{ runRandom::(StdGen -> (a , StdGen)) }

然后你可以像这样得到它

runRandom x --returns the function

或像这样使用

runRandom x gen

答案 3 :(得分:1)

您可以在Rand构造函数上匹配:

getRand :: Rand a -> (StdGen -> (a, StdGen))
getRand (Rand f) = f

您需要一个实例StdGen才能从结果函数中获取a的值。您可以使用mkStdRandom例如

genWith :: Rand a -> Int -> a
genWith (Rand f) = fst . f . mkStdGen