有没有办法在Haskell中解包以下类型?
newtype Rand a = Rand(StdGen -> (a , StdGen))
我有一个返回此类型的功能,另一个我想使用' a'返回函数的值,但我无法弄清楚如何提取值。
答案 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