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

Haskell Monad中`let .. in do`与`<-`的区别及字符串转Maybe Int列表报错解决

Great questions! Let's break them down one by one clearly.

1. Difference between let .. in do and <- in Haskell Monads

The core distinction lies in what they handle—pure values vs. monadic contexts:

  • The <- operator: This is used to extract a pure value out of a monadic wrapper. For example, if you have a value of type m a (like Just 5 or [1,2,3]), <- lets you bind the inner a value to a variable so you can work with it directly in the do block.

    Example with the Maybe monad:

    addMaybe :: Maybe Int -> Maybe Int -> Maybe Int
    addMaybe mx my = do
      x <- mx  -- Extracts Int from mx (if mx is Just x)
      y <- my  -- Extracts Int from my (if my is Just y)
      return (x + y)  -- Wraps the result back in Maybe
    

    Here, x and y are pure Int values, not Maybe Int.

  • let bindings in do blocks: These are for binding pure values that don't live inside a monad. In a do block, you can omit the in keyword for brevity—let x = ... just creates a pure variable that you can use anywhere in the rest of the block, no monadic context required.

    Example using the same Maybe monad:

    addPure :: Maybe Int
    addPure = do
      let x = 3  -- Pure Int, no monadic wrapper
      let y = 4  -- Another pure Int
      return (x + y)  -- Wraps the sum in Maybe, resulting in Just 7
    

    Here, x and y are pure values from the start—we never extract them from a monadic type.

To summarize: Use <- when you need to unwrap a value from a monad (m a → a), and use let when you're working with pure expressions that don't need unwrapping.


2. Fixing the readInts function error

Let's first unpack why your code is throwing that type error:

Your initial code:

readInts (s::String) = do { ws <- words s; return (map (readMaybe::(String -> Maybe Int)) ws) }

The root cause

When you use ws <- words s in a do block, Haskell infers that you're working with the list monad ([]), since your intended return type is [Maybe Int]. In the list monad, <- iterates over each element of the list—so ws isn't the entire list of words (type [String]), but a single word (type String). Then you try to pass this single String to map, which expects a list as its second argument—hence the type mismatch (Expected type: [String], Actual type: String).

The fix

You have two clean ways to implement this correctly:

Option 1: Skip the do block (simplest)

Since you just need to map readMaybe over the list of words, you don't need a do block at all. Just compose the functions directly:

import Text.Read (readMaybe)

readInts :: String -> [Maybe Int]
readInts = map readMaybe . words

This takes the input string, splits it into words with words, then applies readMaybe to each word—exactly what your example expects.

Option 2: Use the do block correctly (if you prefer monadic syntax)

If you want to use a do block with the list monad, you need to process each word individually and return the Maybe Int for each one:

import Text.Read (readMaybe)

readInts :: String -> [Maybe Int]
readInts s = do
  word <- words s  -- Iterate over each word in the list
  return (readMaybe word)  -- Return the Maybe Int for each word

Here, the list monad automatically collects all the return results into a single [Maybe Int] list, which matches your desired output.

Either approach will produce the correct result: readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing]


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:39:36