我正在尝试为状态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的类型,但我希望计算结果有所变化。
发布于 2019-05-17 09:24:13
你的想法还不完全清楚,但根据这些评论,以下是一些建议。
参数化函数
如前所述,f返回(Int, String),您不能仅仅改变这一点。然而,你能做的是把它参数化:
f' :: a -> a -> Int -> (Int, a)
f' bigger smaller x | x > 3 = (x, bigger)
| otherwise = (x, smaller)这个变体不再返回(Int, String),而是返回(Int, a)。然而,您所付出的代价是您必须提供bigger和smaller作为参数。稍后我们将返回到这一点,但在此之前,我们可以将具有通用类型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类型。
返回
从其他评论来看,您似乎希望在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")这只改变了单变量,而不是“返回类型”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)现在可以运行计算,并使用String从Identity中提取runIdentity。
函子
如果你把State s也变成函子,你可以把String从Identity中拉出来。
*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...or,你可以用mtl包的Control.Monad.State.Lazy .
https://stackoverflow.com/questions/56181862
复制相似问题