如何组合二元和一元函数以获得折叠的阶跃函数?
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
),因为它太冗长并且给参数命名(a
和 x
) 确实不需要给一个,而是作为其他函数的"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 更短,但仍然比所有完全无点的版本更具可读性。
阅读 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
),因为它太冗长并且给参数命名(a
和 x
) 确实不需要给一个,而是作为其他函数的"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 更短,但仍然比所有完全无点的版本更具可读性。