do thread 中的`f :: a -> IO ()` 评估:Haskell

`f :: a -> IO ()` evaluation in do thread : Haskell

这是我之前问题的转贴(被我自己删除了),因为我认为通过下面的示例代码来改变焦点就足够了。

基本上,我尝试实现 a 仿函数,它采用 id\a -> a + 1 甚至 print 等函数。

所以函数类型可以是

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

输出

"-- someFunctor"
5
"done"

当前的示例代码没有错误,我想达到的是评估

f val

哪里

  1. f val是包装到新容器中的值ioBio $ f val

  2. 但是由于Haskell的惰性求值策略或者其他原因,在f == print时并没有真正执行,所以val没有按我的预期打印。

  3. 到目前为止,我做了 return $ f val,但这与正在工作的 print val.

    不同
  4. 只是 do 线程中的 f val 并不顺利,因为 f 可以是 id 在这种情况下,它不是 IO 类型。类型不匹配。谢天谢地,编译器在这里巧妙地产生了一个错误。

  5. 所以,我的问题是 generic 实现 f val 的方法是什么 f == print f :: a -> IO ()?

如果你想做 IO,你必须承认你正在做 IO

someFunctor :: Show a => (a -> IO b) -> IO (R a) -> IO (R b)
someFunctor = \f -> \ioA -> do
    {- ... -}
    b <- f val
    io b

您可以将非 IO 函数提升为具有 returnIO 函数,如

someFunctor (return . id)