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

PureScript中do notation使用困惑:等价改写为何触发类型错误?

PureScript中do块使用lines函数的类型错误问题解析

问题重现

第一段可正常运行的代码:

module Main where

import Prelude

import Data.String.Common (joinWith)
import Data.String.Utils (lines)
import Effect (Effect)
import Effect.Console (log)

contents :: String
contents = "1 2\n3 4"

l :: Array String
l = lines contents

main :: Effect Unit
main = do
  log (joinWith "\n" l)

将l移至do块内使用l <- lines contents改写后,出现类型错误:

module Main where

import Prelude

import Data.String.Common (joinWith)
import Data.String.Utils (lines)
import Effect (Effect)
import Effect.Console (log)

contents :: String
contents = "1 2\n3 4"

main = do
  l <- lines contents
  log (joinWith "\n" l)

编译器报错:

Could not match type

    String

  with type

    Array String

while checking that type String
  is at least as general as type Array String
while checking that expression l
  has type Array String
in value declaration main

错误原因

核心问题在于do块里的<-符号的用途:它是用来提取monadic上下文(比如Effect、Maybe这类容器类型)内部的值,要求右侧的表达式必须是m a类型(比如Effect String),而非纯值类型。

lines是纯函数,类型为String -> Array String,接收字符串后直接返回Array String纯值,没有任何monadic上下文。但main的类型是Effect Unit,do块会强制要求<-右侧的表达式属于Effect类型,因此编译器会强行把lines contents的类型推断为Effect String——这就产生了矛盾:lines实际返回的是Array String,却被编译器当成了Effect String,通过<-提取出的l便被推断为String类型,而后续joinWith需要的是Array String,自然出现类型不匹配错误。

修正方案

因为lines是纯函数,不需要monadic绑定,直接在do块里用let声明变量即可:

module Main where

import Prelude

import Data.String.Common (joinWith)
import Data.String.Utils (lines)
import Effect (Effect)
import Effect.Console (log)

contents :: String
contents = "1 2\n3 4"

main = do
  let l = lines contents
  log (joinWith "\n" l)

这样l的类型会被正确推断为Array String,代码可正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:32:44