'/usr/local/lib/node'
我无法理解上述代码中读取函数的含义
答案 0 :(得分:6)
注意:所有
toDigits
此处仅使用正数(包括零),并且在负数上会出错。
read
有签名:
read :: Read a => String -> a
因此,根据签名,我们可以说如果a
类型为Read a
,则会将String
转换为a
。在自然语言中,它意味着它解析对象到该对象的文本表示。例如,它可以将"\"foo\""
解析为字符串"foo"
。或者它可以将"23"
解析为整数23
。输出类型决定了我们解析元素的内容,但根据函数,它可能有一些类型签名toDigits :: Int -> Int
。
现在我们仍然需要了解该功能的工作原理。 show :: Show a => a -> String
实际上与read
相反:它将对象转换为文本表示。因此,23
例如转换为"23"
,String
。
首先我们将一个数字转换为1425
,例如"1425"
。 String
是Char
的列表,或更正式的type String = [Char]
。这意味着我们可以对其执行map
,因此map
将处理Char
的每个String
,一次一个。{/ p>
现在,对于每个字符c
,我们首先构建一个列表[c]
。我们为什么这样做?使它成为String
。由于String
是一个字符列表。具有一个字符的列表等于具有该字符的字符串。接下来,我们调用1-char字符串上的read,将其转换为我们喜欢的任何内容。
这意味着toDigits
具有最通用的类型:
toDigits :: (Show a, Read b) => a -> [b]
请注意,根据此签名,我们不受a
应该是数字,输出应该是数字这一事实的限制。只要a
对象的文本表示可以拆分为1-char字符串,可以单独解析为b
的对象,我们就可以了。但实际上,如果a
和b
都是Integral
,那么它可能才有意义,所以:
toDigits :: (Show a, Read b, Integral a, Integral b) => a -> [b]
最后要注意的是,我们可以使实现更加优雅,例如:
toDigits :: (Show a, Read b, Integral a, Integral b) => a -> [b]
toDigits = map (read . pure) . show
我们可以进一步将输出类型限制为Int
,因为Int
保证在(和包括)0和9之间包含所有数字,并构造:
import Data.Char(digitToInt)
toDigits :: (Show a, Integral a) => a -> [Int]
toDigits = map digitToInt . show
话虽如此,该函数做出了一些假设:例如,所有数字都将具有十进制表示法的文本表示。这本身并不能保证:我可以构建自己的数字系统,并决定构建一个例如使用一元系统的节目(虽然这可能不是一个好主意)。这使得它有点像危险方法:你依赖于一些无法保证的假设。此外,这个
我们可以使用div
和mod
来计算数字。比如:
toDigits :: Integral a => a -> [a]
toDigits 0 = [0]
toDigits n | n < 0 = error "Negative number!"
| otherwise = step [] n
where step xs 0 = xs
step xs d = step ((mod d 10):xs) (div d 10)
此外,我们删除了Show a
类型约束,因此仍然可以处理没有此类show
的积分。