最近,我试图在我的一些真实案例制作系统中使用Haskell。 Haskell类型系统确实为我提供了很大的帮助。例如,当我意识到我需要一些类型为type的函数时
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
实际上有
foldM
,foldlM
和foldrM
之类的功能。
但是,真正令我震惊的是这些功能的定义,例如:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b foldlM f z0 xs = foldr f' return xs z0 where f' x k z = f z x >>= k
所以功能
f'
必须是类型:
f' :: a -> b -> b
根据
foldr
的要求,然后b
必须为*-> m *
类型,因此foldlM
的整个定义可能是有意义的。
另一个示例包括liftA2
和<*>
的定义
(<*>) :: f (a -> b) -> f a -> f b (<*>) = liftA2 id liftA2 :: (a -> b -> c) -> f a -> f b -> f c liftA2 f x = (<*>) (fmap f x)
在查看源代码之前,我尝试了一些自己的解决方案。但是差距是如此之大,以至于我以后再写多少行代码都无法提出这种解决方案。
因此,我的问题是,在如此高度抽象的水平上进行推理的人需要哪种知识或特定的数学分支。
[我知道类别理论可能会提供一些帮助,并且我一直关注this great lecture很长时间了,但仍在研究之中。
最近,我试图在我的一些真实案例制作系统中使用Haskell。 Haskell类型系统确实为我提供了很大的帮助。例如,当我意识到我需要某种类型为f :: ...
所以理解它的最好方法就是这样做。下面是使用foldlM
而不是foldl
的foldr
实现。这是一个很好的练习,请尝试一下,然后再提出我建议的解决方案。该示例说明了我为实现此目标所做的所有推理,这可能与您的不同,并且可能有偏见,因为我已经知道使用函数累加器。
您不需要任何数学方面的专门知识即可编写类似foldM
的函数。我已经在生产环境中使用Haskell已有4年了,并且我也很难理解foldM
的定义。但这主要是因为它写得不好。请,如果您无法理解一些晦涩的代码,请不要将其视为个人过失。这是foldlM
]的可读性更高的版本
foldlM :: forall t m a b . (Foldable t, Monad m) => (b -> a -> m b) -- ^ Monadic action -> b -- ^ Starting accumulator -> t a -- ^ List of values -> m b -- ^ Computation result inside a monad foldlM f z xs = (foldr step pure xs) z where step :: a -> (b -> m b) -> b -> m b step cur next acc = do result <- f acc cur next result
此功能仍然不是最简单的功能。主要是因为它具有
foldr
的非典型用法,其中中间累加器是一个函数。但是您会看到一些使这种定义更易读的可能: