如何为 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)。然而,您付出的代价是您必须提供 biggersmaller 作为参数。我们稍后会 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 StringState 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...