如何组合二元和一元函数以获得折叠的阶跃函数?

How to combine binary and unary function to obtain the step function for a fold?

阅读 Chapter 4 from Real World Haskell 时,我完成了第 97 页的练习 1,其中包含以下几行

asInt :: String -> Int
asInt ('-':x) = asInt x
asInt xs = foldl (\a x -> a*10 + digitToInt x) 0 xs

然后我查看了链接页面的一些评论,确认这是大多数人采用的解决方案。

另一方面,我认为最好不要将函数编写为 lambda (\a x -> a*10 + digitToInt x),因为它太冗长并且给参数命名(ax) 确实不需要给一个,而是作为其他函数的"combination",即二元函数(*)(+)和一元函数digitToInt;但是我不知道如何将这三个组合成一个与上面的 lambda 等效的二元函数。

我认为组成的成分是 (*10),必须作用于 foldl 的累加器的一元函数,digitToInt,作用于元素的一元函数列表 xs(+),必须将这两者结合起来。

如果在 调用 foldl:

之前将每个数字转换为整数 ,则更简单
asInt xs = foldl (\a x -> a*10 + x) 0 (map digitToInt xs)
    -- == foldl ((+) . (10 *)) 0 (map digitToInt xs)

您可以进一步将其转换为

asInt = foldl ((+) . (10 *)) 0 . map digitToInt

(我相信,由于列表融合,map 不会创建中间列表。每次调用 digitToInt 的输出都会立即被 [=12 使用=],而不是放入列表。)

(您想了解无意义函数的工作原理,所以在这里。)

第一。

(\a x -> a*10 + digitToInt x)
= 
(\a x -> (+) ((*10) a) (digitToInt x))
= 
(curry $ (+) . (*10) . fst <*> digitToInt . snd)
=
(curry $ uncurry (+) . ((*10) *** digitToInt))

第二

(\a x -> a*10 + digitToInt x)
= 
(\a x -> (+) ((*10) a) (digitToInt x))
= 
(\a x -> ((+) . (*10)) a . digitToInt $ x)
= 
(\a   -> ((+) . (*10)) a . digitToInt    )
= 
(\a   -> (. digitToInt) ( ((+) . (*10)) a ) )
= 
(\a   -> (. digitToInt) . ((+) . (*10)) $ a )
= 
         (. digitToInt) .  (+) . (*10)

它是如何工作的

第一。

(curry $ (+) . (*10) . fst <*> digitToInt . snd)  a  x
= {-  curry f a b  =  f (a, b)                               -}
        ((+) . (*10) . fst <*> digitToInt . snd) (a, x)
= {-  (f <*> g) a  =  f a (g a)   ;   (f . g) a  =  f (g a)  -}
   ((+) . (*10)) (fst (a, x)) (digitToInt ( snd  (a, x)))
=
   ((+) . (*10))       a      (digitToInt            x  )
= {-  (f . g) a  =  f (g a)   ;   (`c` b) a  =  (a `c` b)    -}
    (+)   (a*10)              (digitToInt            x  )
= {-  (c) a b  =  (a `c` b)                                  -}
          (a*10)            +  digitToInt            x

并且,

(curry $ uncurry (+) . ((*10) *** digitToInt))  a  x
= {-  curry f a b  =  f (a, b)                -}
        (uncurry (+) . ((*10) *** digitToInt)) (a, x)
= {-  (f *** g) a  =  (f $ fst a, g $ snd a)  -}
         uncurry (+) (  (*10) a , digitToInt       x )
= {-  uncurry f (a, b)  =  f a b              -}
                 (+) (  (*10) a) (digitToInt       x )
= {-  (`c` b) a  =  (a `c` b)                 -}
                 (+)   (a*10)    (digitToInt       x )
= {-  (c) a b  =  (a `c` b)                   -}
                       (a*10)  +  digitToInt       x

第二

           ((. digitToInt) . (+) . (*10)) a x
= {-  (f . g) a  =  f (g a)     -}
           ((. digitToInt) . (+)) ((*10) a) x
= {-  (`c` b) a  =  (a `c` b)   -}
           ((. digitToInt) . (+)) (a*10)    x
= {-  (f . g) a  =  f (g a)     -}
            (. digitToInt) ( (+)  (a*10) )  x
= {-  (`c` b) a  =  (a `c` b)   -}
 ((+) (a*10) . digitToInt)                  x
= {-  (f . g) a  =  f (g a)     -}
  (+) (a*10) ( digitToInt                   x )
= {-  (c) a b  =  (a `c` b)     -}
      (a*10) + digitToInt                   x  

另一种可能性是部分无点,

foldl  (\a -> (a*10 +) . digitToInt)  ...

它比完整的 lambda 更短,但仍然比所有完全无点的版本更具可读性。