无法匹配foldl

时间:2016-05-11 03:17:19

标签: haskell fold

我有以下代码,它应该将excel列类型转换为相应的数字。例如AA到27和AB到28:

import Data.Char (ord)
import Data.List (foldl1')

columnToNumber :: String -> Int
columnToNumber s = foldl1' (\acc (i, v) -> acc + 26 ^ i * v) (values s)
  where values s = zip (reverse [0..(length s)]) ((\c -> ord c - 64) <$> s)

这个想法是采取字符串&#34; AA&#34;将其转换为相应的数字

["A", "A"] -> [1, 1]

并用基座拉链,从右到左依次为26 ^ 0,26 ^ 1,26 ^ 2,等等。

zip [1, 0] [1, 1] -> [(1, 1), (0, 1)]

这样折叠的结果将是

26^1 * 1 + 26^0 * 1 = 27

不幸的是,我收到了以下错误,我不确定原因:

ExcelSheetColumn.hs:7:34:
    Couldn't match expected type ‘Int’
                with actual type ‘(Integer, Int)’
    In the pattern: (i, v)
    In the first argument of ‘foldl1'’, namely
      ‘(\ acc (i, v) -> acc + 26 ^ i * v)’
    In the expression:
      foldl1' (\ acc (i, v) -> acc + 26 ^ i * v) (values s)

ExcelSheetColumn.hs:7:63:
    Couldn't match type ‘(Int, Int)’ with ‘Int’
    Expected type: [Int]
      Actual type: [(Int, Int)]
    In the second argument of ‘foldl1'’, namely ‘(values s)’
    In the expression:
      foldl1' (\ acc (i, v) -> acc + 26 ^ i * v) (values s)

有人可以帮助我吗?

2 个答案:

答案 0 :(得分:6)

要让它进行编译,您实际上只需将foldl1'切换为foldl'并添加开始累加器:

import Data.Char (ord)
import Data.List (foldl')

columnToNumber :: String -> Int
columnToNumber s = foldl' (\acc (i, v) -> acc + 26 ^ i * v) 0 (values s)
  where values s = zip (reverse [0..(length s)]) ((\c -> ord c - 64) <$> s)

如果您添加了建议Free_D(从length s - 1开始):

columnToNumber :: String -> Int
columnToNumber s = foldl' (\acc (i, v) -> acc + 26 ^ i * v) 0 (values s)
  where values s = zip (reverse [0..(length s -1)]) ((\c -> ord c - 64) <$> s)

你得到了预期的结果:

λ> columnToNumber "AA"
27
λ> columnToNumber "AB"
28

我不知道你是否真的需要这个但是嘿,为什么不呢:

您可能不喜欢的是columnToNumber "A1"11 - 为了解决这个问题,您需要使用不同于字母的数字:

columnToNumber :: String -> Int
columnToNumber s = foldl' (\acc (i, v) -> acc + 26 ^ i * v) 0 (values s)
  where values s = zip (reverse [0..(length s -1)]) (parse <$> s)
        parse c
          | c >= '0' && c <= '9' = ord c - ord '0'
          | otherwise = ord c - 64

答案 1 :(得分:2)

看一下// ... stuff else if ( distanceX < 0 ) { $div.css({ 'left': e.clientX, 'top': e.clientY - distanceY, 'width': (1 - distanceX), 'height': distanceY }); } else if ( distanceY < 0 ) { $div.css({ 'left': e.clientX - distanceX, 'top': e.clientY, 'width': distanceX, 'height': (1 - distanceY) }); } 的定义,它必须采取两种相同类型的东西并产生类似的东西

foldl1'

但是*Main Data.List> :t foldl1' foldl1' :: (a -> a -> a) -> [a] -> a 就是你想要的:

foldl

基本上就是这样:

*Main Data.List> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b