You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell syb库mkM使用方法及传入自定义函数报错问题求解

错误原因分析

  • printMyInt传入mkM报错的核心原因是类型不匹配:mkM要求传入的函数签名为b -> m b,即输入类型和Monad包裹的输出类型必须一致,都为b。而你定义的printMyInt签名是MyInt -> IO (),输出的Monad包裹值类型是(),和输入的MyInt不匹配,GHC因此抛出类型匹配错误。
  • pure传入mkM报错是因为类型推导歧义:pure本身是多态函数,签名为Applicative f => a -> f a,没有显式指定类型的情况下,GHC无法确定你要匹配的b具体是什么类型,自然无法满足Typeable b的约束,因此抛出实例缺失错误。

正确使用mkM的方式

1. 修正函数签名适配mkM要求

如果需要在遍历过程中打印值同时保留原值,可以修改打印函数返回Monad包裹的输入值:

printMyInt' :: MyInt -> IO MyInt
printMyInt' mi@(MyInt i) = do
  putStrLn $ "MyInt = " ++ show i
  pure mi

此时查询类型即可正常通过:

> :t mkM printMyInt'
mkM printMyInt' :: (MonadIO m, Typeable a) => a -> m a

2. 多态函数显式指定类型

如果要使用pure这类多态函数,可以通过类型签名或者类型应用固定要匹配的类型:

-- 方式1:给pure加签名固定类型
> :t mkM (pure :: MyInt -> IO MyInt)
mkM (pure :: MyInt -> IO MyInt) :: Typeable a => a -> IO a

-- 方式2:开启TypeApplications扩展直接指定类型参数
> :set -XTypeApplications
> :t mkM @MyInt pure
mkM @MyInt pure :: (Monad m, Typeable a) => a -> m a

3. 配合遍历函数使用示例

mkM通常和everywhereM等遍历函数配合使用,处理嵌套数据结构:

-- 定义包含MyInt的嵌套结构
data Foo = Foo MyInt [MyInt] deriving (Show, Data)
testFoo = Foo (MyInt 1) [MyInt 2, MyInt 3]

-- 遍历打印所有MyInt值
> everywhereM (mkM printMyInt') testFoo
MyInt = 1
MyInt = 2
MyInt = 3
Foo (MyInt 1) [MyInt 2,MyInt 3]

内容的提问来源于stack exchange,提问作者Daniil Iaitskov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:45:04