如何为 state-monad 的方法提供泛型类型
How to supply generic type for the state-monad's method
我正在尝试为状态 monad 创建一个 function
,它可以在 a
中接收通用类型:
newtype State s a=State { runstate::s->(s,a) }
我只想绑定 runstate::s->(s,a)
的第一种类型,然后再决定 a
应该是什么 :
所以不要像 :
f::Int->(Int,String)
f x | x>3 = (x, "bigger then 3")
|otherwise =(x,"smaller then 3")
make::State Int String
make =State f
我怎样才能完成:
makeFree::State Int a
makeFree=State ....
您可能想知道我为什么需要它。虽然我知道 state
的类型,但我希望计算结果有所不同。
您的想法并不完全清楚,但根据评论,这里有一些建议。
参数化函数
如前所述,f
returns (Int, String)
,您不能只更改它。然而,你可以做的是对其进行参数化:
f' :: a -> a -> Int -> (Int, a)
f' bigger smaller x | x > 3 = (x, bigger)
| otherwise = (x, smaller)
这个变体不再是 return(Int, String)
,而是 (Int, a)
。然而,您付出的代价是您必须提供 bigger
和 smaller
作为参数。我们稍后会 return,但在我们这样做之前,我们可以将具有通用类型 s -> (s, a)
的任何函数转换为 State s a
值:
make' :: (s -> (s, a)) -> State s a
make' fn = State fn
您现在可以部分应用 f'
来改变类型:
*Q56181862> :t make' $ f' "bigger than 3" "smaller than 3"
make' $ f' "bigger than 3" "smaller than 3" :: State Int [Char]
*Q56181862> :t make' $ f' True False
make' $ f' True False :: State Int Bool
在上面的第一个 GHCi 示例中,类型是 State Int String
,而第二个示例的类型是 State Int Bool
.
Return
从其他评论来看,您似乎希望在 State Int String
和 State Int (IO String)
之间变化。虽然您可以使用上述技术实现这一点,但您也可以在函数本身中使用 return
:
f'' :: Monad m => Int -> (Int, m String)
f'' x | x > 3 = (x, return "bigger than 3")
| otherwise = (x, return "smaller than 3")
这只改变 monad,而不改变 'return type' String
。您可以向 Haskell 的类型系统提供足够的提示,以通知它 m
应该是 IO
:
*Q56181862> :t make' $ f'' :: State Int (IO String)
make' $ f'' :: State Int (IO String) :: State Int (IO String)
如果你不想运行IO
中的计算,你可以在Identity
中运行计算,这也是Monad
]:
*Q56181862 Control.Monad.Identity> :t make' $ f'' :: State Int (Identity String)
make' $ f'' :: State Int (Identity String) :: State Int (Identity String)
您现在可以 运行 计算并使用 runIdentity
.
从 Identity
中提取 String
函子
如果你也使 State s
成为仿函数,你可以从 Identity
:
中提取 String
*Q56181862 Control.Monad.Identity> :t fmap runIdentity $ make' $ f''
fmap runIdentity $ make' $ f'' :: State Int String
最简单的方法是使用 DeriveFunctor
GHC 扩展:
newtype State s a = State { runstate :: s -> (s, a) } deriving Functor
...或者,您可以只使用 mtl
包中的 Control.Monad.State.Lazy
...
我正在尝试为状态 monad 创建一个 function
,它可以在 a
中接收通用类型:
newtype State s a=State { runstate::s->(s,a) }
我只想绑定 runstate::s->(s,a)
的第一种类型,然后再决定 a
应该是什么 :
所以不要像 :
f::Int->(Int,String)
f x | x>3 = (x, "bigger then 3")
|otherwise =(x,"smaller then 3")
make::State Int String
make =State f
我怎样才能完成:
makeFree::State Int a
makeFree=State ....
您可能想知道我为什么需要它。虽然我知道 state
的类型,但我希望计算结果有所不同。
您的想法并不完全清楚,但根据评论,这里有一些建议。
参数化函数
如前所述,f
returns (Int, String)
,您不能只更改它。然而,你可以做的是对其进行参数化:
f' :: a -> a -> Int -> (Int, a)
f' bigger smaller x | x > 3 = (x, bigger)
| otherwise = (x, smaller)
这个变体不再是 return(Int, String)
,而是 (Int, a)
。然而,您付出的代价是您必须提供 bigger
和 smaller
作为参数。我们稍后会 return,但在我们这样做之前,我们可以将具有通用类型 s -> (s, a)
的任何函数转换为 State s a
值:
make' :: (s -> (s, a)) -> State s a
make' fn = State fn
您现在可以部分应用 f'
来改变类型:
*Q56181862> :t make' $ f' "bigger than 3" "smaller than 3"
make' $ f' "bigger than 3" "smaller than 3" :: State Int [Char]
*Q56181862> :t make' $ f' True False
make' $ f' True False :: State Int Bool
在上面的第一个 GHCi 示例中,类型是 State Int String
,而第二个示例的类型是 State Int Bool
.
Return
从其他评论来看,您似乎希望在 State Int String
和 State Int (IO String)
之间变化。虽然您可以使用上述技术实现这一点,但您也可以在函数本身中使用 return
:
f'' :: Monad m => Int -> (Int, m String)
f'' x | x > 3 = (x, return "bigger than 3")
| otherwise = (x, return "smaller than 3")
这只改变 monad,而不改变 'return type' String
。您可以向 Haskell 的类型系统提供足够的提示,以通知它 m
应该是 IO
:
*Q56181862> :t make' $ f'' :: State Int (IO String)
make' $ f'' :: State Int (IO String) :: State Int (IO String)
如果你不想运行IO
中的计算,你可以在Identity
中运行计算,这也是Monad
]:
*Q56181862 Control.Monad.Identity> :t make' $ f'' :: State Int (Identity String)
make' $ f'' :: State Int (Identity String) :: State Int (Identity String)
您现在可以 运行 计算并使用 runIdentity
.
Identity
中提取 String
函子
如果你也使 State s
成为仿函数,你可以从 Identity
:
String
*Q56181862 Control.Monad.Identity> :t fmap runIdentity $ make' $ f''
fmap runIdentity $ make' $ f'' :: State Int String
最简单的方法是使用 DeriveFunctor
GHC 扩展:
newtype State s a = State { runstate :: s -> (s, a) } deriving Functor
...或者,您可以只使用 mtl
包中的 Control.Monad.State.Lazy
...