为什么 map 使用的这个函数需要返回一个(单例)列表而不是一个元素?

Κωσ*_*ρης 2 haskell

您可能已经猜到了,完全是初学者。我已经完成了“Learn you a Haskell”,但我仍然在基础知识上挣扎。

我正在看这个线程 用 Haskell 将一个数字拆分成它的数字 ,这个函数开始变得有意义了

digits :: Integer -> [Int]
digits n = map (\x -> read [x] :: Int) (show n)
Run Code Online (Sandbox Code Playgroud)

丹尼尔问。

我知道 show 将我的输入数字作为字符串或字符列表返回,然后我可以使用 map 逐个修改元素。因此,每个“x”,作为一个字符,被匿名函数选择并读取为一个整数,新列表由 map 组成,包含所有读取的整数。那不read [x]应该read x吗?为什么列表中的每个读取 Char 都需要作为它自己的单例列表返回?在我看来,这种调用方式digits 123应该返回[[1],[2],[3]],因为 map 无论如何都会将所有内容组合到一个新列表中,而不是[1,2,3]像它正确的那样。但为什么?

bra*_*drn 5

让我们来看看类型read

Prelude> :t read
read :: Read a => String -> a
Run Code Online (Sandbox Code Playgroud)

也就是说,对于a作为 实例的任何类型Read,该read函数可用于将 a 转换String为该类型的成员。请注意,这里的参数read是 a String- 而不是 a Char!因此,为了使用 将 a 转换Char为其他类型read,您首先需要将 转换Char为 a String。你是怎么做到的?好吧,请记住, aString只是Chars:的列表type String = [Char]。因此,您可以通过Char将 aString包装在一个列表中来将其转换为 a — 这正是您的代码所做的。您可以在 GHCi 中自己确认这是必要的:

Prelude> read '1' :: Int

<interactive>:10:6: error:
    * Couldn't match type `Char' with `[Char]'
      Expected type: String
        Actual type: Char
    * In the first argument of `read', namely '1'
      In the expression: read '1' :: Int
      In an equation for `it': it = read '1' :: Int
Prelude> read "1" :: Int
1
Prelude> read ['1'] :: Int
1
Prelude> :t ['1']
['1'] :: [Char]
Prelude> :t "1"
"1" :: [Char]
Prelude> :t '1'
'1' :: Char
Run Code Online (Sandbox Code Playgroud)

(顺便说一下,我应该注意到你的代码摘要的其余部分是完全正确的。)


Wil*_*sem 5

read :: Read a => String -> a适用于 a String,而不适用于 a Char,这里xChar.

实际上,show n构造 a String,它是Chars的列表,因为type String = [Char]。如果我们对Chars的列表执行映射,则映射函数中的x是 a Char。我们将它包装在一个单例列表中以构造一个String带有一个Char演员的 a,然后使用read该字符串作为Int.

然而,我们可以使用digitToInt :: Char -> Int它可能更高效和优雅:

import Data.Char(digitToInt)

digits :: Integer -> [Int]
digits = map digitToInt . show
Run Code Online (Sandbox Code Playgroud)