【发布时间】:2021-03-14 02:57:57
【问题描述】:
为什么 ghc 不抱怨以下函数中的类型是刚性的?
play :: (Monad m, MonadIO m, Random a) => a -> a -> m a
play r1 r2 = do
randomRIO (r1, r2)
在上述情况下,m 实际上是IO。此代码编译。而其他时候,当我在泛型函数中使用具体类型时,ghc 会抱怨我使用的是具体类型。我错过了什么吗?
例如,如果我说:
play :: (Monad m, MonadIO m, Random a) => a -> a -> m a
play r1 r2 = do
randomRIO (1, 6::Int)
这一次 ghc 抱怨我使用的是刚性类型。困扰我的是IO 在某种程度上是具体的或刚性的类型,因为它是IO 而不是Maybe。
编辑 1: 编译无误的完整代码:
{-# LANGUAGE ConstraintKinds #-}
module Main where
-- showing how to program in the mtl style
import Control.Monad.IO.Class
import System.Random
type Game m a = (Monad m, MonadIO m, Random a, Show a)
-- step 1
play :: (Game m a) => a -> a -> m a
play r1 r2 = do
yell "hi"
randomRIO (r1, r2)
--rollDice r1 r2
-- step 2
yell :: (MonadIO m) => String -> m ()
yell str = liftIO $ putStrLn str
-- step 3
rollDice :: (Game m a) => a -> a -> m a
rollDice a1 a2 = liftIO $ randomRIO (a1,a2)
main :: IO ()
main = putStrLn ""
-- main :: IO ()
-- main = do
-- play 1 (6::Int) >>= print
-- play 'a' 'z' >>= print
-- putStrLn "done"
Code that doesn't compile:
{-# LANGUAGE ConstraintKinds #-}
module Main where
-- showing how to program in the mtl style
import Control.Monad.IO.Class
import System.Random
type Game m a = (Monad m, MonadIO m, Random a, Show a)
-- step 1
play :: (Game m a) => a -> a -> m a
play r1 r2 = do
yell "hi"
randomIO 'a' 'z'
--rollDice r1 r2
-- step 2
yell :: (MonadIO m) => String -> m ()
yell str = liftIO $ putStrLn str
-- step 3
rollDice :: (Game m a) => a -> a -> m a
rollDice a1 a2 = liftIO $ randomRIO (a1,a2)
main :: IO ()
main = putStrLn ""
-- main :: IO ()
-- main = do
-- play 1 (6::Int) >>= print
-- play 'a' 'z' >>= print
-- putStrLn "done"
这不能编译:
{-# LANGUAGE ConstraintKinds #-}
module Main where
-- showing how to program in the mtl style
import Control.Monad.IO.Class
import System.Random
type Game m a = (Monad m, MonadIO m, Random a, Show a)
-- step 1
play :: (Game m a) => a -> a -> m a
play r1 r2 = do
yell "hi"
**randomRIO (1, 6::Int)**
--rollDice r1 r2
-- step 2
yell :: (MonadIO m) => String -> m ()
yell str = liftIO $ putStrLn str
-- step 3
rollDice :: (Game m a) => a -> a -> m a
rollDice a1 a2 = liftIO $ randomRIO (a1,a2)
main :: IO ()
main = putStrLn ""
-- main :: IO ()
-- main = do
-- play 1 (6::Int) >>= print
-- play 'a' 'z' >>= print
-- putStrLn "done"
更新
刚刚意识到我的困惑来自于阅读了错误的 random 文档
在我的代码中使用random-1.2 时,我正在阅读random-1.1 文档。
供大家参考:
random-1.1
randomRIO :: (a, a) -> IO a
random-1.2
randomRIO :: (Random a, MonadIO m) => (a, a) -> m a
【问题讨论】:
-
你使用
m a,这意味着m是一个接受一个类型,然后产生一个具体类型的东西。例如,您可以使用IO、Maybe、[]等。虽然这里Maybe和[]当然不会满足MonadIO类型约束。 -
@WillemVanOnsem 如果我说 randomRIO (1,2::Int),ghc 会抱怨。所以我可以将
m设为具体类型,但不能将a设为? -
如果你不确定它有什么问题,为什么不分享不编译的代码?就目前而言,这里没有什么要回答的。
-
@daydaynatation:不,
IO不是具体类型。您可以创建IO Int、IO ()等,但不能创建IO。因此,IO基本上是一个接受类型(Int、()等)并产生类型的函数。m因此有种m :: * -> *。 -
"m 实际上是 IO"。上面的代码不需要
m是IO。它允许m成为IO(或其他任何MonadIO)。因此,如果您以强制m为IO的方式调用此代码,实际上没有问题。如果您有一些无法编译的代码并且您不明白为什么,那么如何显示该代码?
标签: haskell