This is a repost of my previous question(deleted by myself) since I considered it would be adequate to change the focus by presenting the sample code below.
Basically, I try to implement a Functor that takes a function such as id, \a -> a 1 or even print .
So the function type can be
f :: a -> b
f :: a -> IO ()
module Main where
import Control.Monad.Primitive (PrimMonad (PrimState))
import qualified Data.Vector.Mutable as M
import System.IO.Error (isDoesNotExistErrorType)
main :: IO ()
main = do
let ioA = io (5 :: Int)
let f = print
-- f = \a -> a 1
let ioB = someFunctor f ioA
ioB
print "done"
data R a = R
{ val :: M.MVector (PrimState IO) a
}
io :: a -> IO (R a)
io = \a -> do
val <- M.new 1
M.write val 0 a
return $ R val
_val :: R a -> IO a
_val = \ra -> M.read (val ra) 0
someFunctor :: Show a => (a -> b) -> IO (R a) -> IO (R b)
someFunctor = \f -> \ioA -> do
print "-- someFunctor"
val <- ioA >>= _val
print val --works 5
let ioB = io $ f val
--here, I want to actually `print val` when `f == print`
return $ f val
ioB
Output
"-- someFunctor"
5
"done"
The current sample code woks without errors, and what I want to achieve is to evaluate
f val
where
f valis the value wrapped into the new containerioB:io $ f valHowever, due to the lazy-evaluation strategy of Haskell or some other reason, when
f == print, this is not actually performed, so thevalis not printed against my expectation.So far, I did
return $ f val, but this does not work unlike the workingprint val.Just
f valindothread doesn't go well becausefcan beidand in that case, it's notIOtype. Type mismatch. The compiler smartly generates an error here thanksfully.So, my question is what is the generic way to implement
f valto be evaluated whenf == printf :: a -> IO ()?
CodePudding user response:
If you want to do IO, you have to admit you're doing IO.
someFunctor :: Show a => (a -> IO b) -> IO (R a) -> IO (R b)
someFunctor = \f -> \ioA -> do
{- ... -}
b <- f val
io b
You can lift non-IO functions to IO ones with return, as in
someFunctor (return . id)
