任何人都可以在haskell的以下代码中解释读取函数的含义

时间:2017-09-20 17:19:42

标签: haskell

'/usr/local/lib/node'

我无法理解上述代码中读取函数的含义

1 个答案:

答案 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"StringChar列表,或更正式的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的对象,我们就可以了。但实际上,如果ab都是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

话虽如此,该函数做出了一些假设:例如,所有数字都将具有十进制表示法的文本表示。这本身并不能保证:我可以构建自己的数字系统,并决定构建一个例如使用一元系统的节目(虽然这可能不是一个好主意)。这使得它有点像危险方法:你依赖于一些无法保证的假设。此外,这个

我们可以使用divmod来计算数字。比如:

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的积分。