- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
各种优化问题,如this one ,导致了 Church 编码列表作为实现流融合的一种方式,即编译器消除中间结果(例如列表)。以下是在优化问题中成功使用的定义:
{-# LANGUAGE RankNTypes #-}
-- A list encoded as a strict left fold.
newtype ListL a = ListL {build :: forall b. (b -> a -> b) -> b -> b}
我对教会事物的看法是这样的:不要问“某物”是什么,而是问它能为你做什么。对于列表,答案是:列表可以折叠。为了折叠,我需要一个 b->a->b
类型的“更新”函数以及 b
类型的起始值。然后我会给你返回折叠的结果,其类型为 b
。因此 ListL
的定义。下面是对ListL
的一些基本操作:
mapL :: (a -> a') -> ListL a -> ListL a'
mapL f l = ListL (\f' b' -> build l (\b a -> f' b (f a)) b')
instance Functor ListL where fmap = mapL
fromList :: [a] -> ListL a
fromList l = ListL (\c z -> foldl' c z l)
toList :: ListL a -> [a]
toList l = build l snoc [] where snoc xs x = xs ++ [x]
nullL :: ListL a -> Bool
nullL l = build l (\_ _->False) True
这里有更多:
filterL :: (a->Bool) -> ListL a -> ListL a
filterL p l = ListL (\f b->build l (\b' a'->if p a' then f b' a' else b') b)
iterUntil :: (a->Bool) -> a -> (a->a) -> ListL a
iterUntil p a f = ListL (\g b-> snd $ until (p.fst) (\(a',b')->(f a', g b' a')) (a,b))
iterUntil
迭代函数a->a
,以 a
类型的某个值开始,直到谓词 a->bool
已实现。像 Prelude 的 iterate
这样的函数不可能的 - 至少我不知道如何定义它,它必须是某种递归。
继续举例,length
和sum
只是在 foldl
中选择正确的“更新”函数和起始值的练习:
lengthL :: ListL a -> Int
lengthL l = build l (\b _ -> b+1) 0
sumL :: Num a => ListL a -> a
sumL l = build l (+) 0
现在,让我们尝试 headL
:
headL :: ListL a -> a
headL l = build l (\_ a->a) _ -- this does not compile!
无论怎样开始b
提供,第一个a
应该被退回。 build l
需要 b
,但我们没有。这是一个奇怪的:基本上我们想告诉编译器:你不需要 b
,相信我... A headL' :: ListL a -> ListL a
另一方面,易于构造。安error "empty list!"
代替孔_
不起作用,因为它总是被调用 - 懒惰似乎并没有解决这个问题。所以,与 headL
我被困住了。因此这里是
问题1:headL
怎么样?实现了吗?
当尝试实现 repeatM :: Monad m => m a -> m [a]
的等效项时,会出现第二个问题。 。与 iterUntil
一样, 谓词 a->Bool
需要停止迭代:
iterUntilM :: Monad m => (a->Bool) -> m a -> m (ListL a)
目的很明确:重复单一 Action m a
直到a->Bool
很满意。当然,这个想法是折叠这个 ListL a
马上实现流融合(列表融合)。例如:
import System.Random (randomIO)
main :: IO ()
main = do
rs <- iterUntilM (>42::Int) randomIO
print $ lengthL rs
该示例相当人为,它打印了找到第一个 >42 的数字之前所花费的抽奖次数。在更现实的设置中,单子(monad) m
例如, ST s
包装一些 FFI 的 monad。要点是:这应该有效运行。我完全被这个困住了。我该如何纠缠(>>=) :: m a -> (a->m b) -> m b
与 build
获得 m (ListL a)
? IE。这是
问题2:iterUntilM
怎么样实现了吗?
除了作为一个很好的学习练习之外,这实际上是一个好主意吗?
最佳答案
一般来说,当您消除对类型的假设时,您编写的函数不仅会更加通用(就其可以使用的类型而言),而且对于什么内容也会更加具体正是它正在做的。这就是允许融合的教堂编码所发生的情况:当列表表示为
data [a] = [] | a : [a]
在函数中使用它们的方法有无数种,其中只有一种是 foldr
。但是,当您有:
newtype List a = { runList :: forall b. (a -> b -> b) -> b -> b }
使用该类型的唯一方法是通过foldr
。这就是您可以进行我们所了解和喜爱的优化的原因。顺便说一下,流融合只是其中之一:例如,您还可以获得 O(1) 追加。
您的类型仍然受到更多限制:它告诉我们底层列表不能(有意义地)无限。
还有另一种列表的约束表示可以转移焦点:
data List a = forall b. List b (b -> Maybe (a, b))
如果教堂编码列表是消费者,那么这是生产者。它没有说明如何使用该列表,但详细说明了如何创建该列表。
所以我们已经看到,我们从这些受限表示中得到了很多,但我们失去了什么? tail
就是一个很好的例子。对于生产者:
tail (List x f) = case f x of
Just (_,xs) -> List xs f
对于消费者来说:
tail xs =
List (\c n ->
runList xs
(\h t g -> g h (t c))
(const n)
(const id))
消费者的实现是O(n),而生产者的实现显然是O(1)。
这两种类型都可以进行融合,但某些功能可以比另一种更有效地实现。 GHC 碰巧选择了前一种表示形式作为融合的基础,但没有任何根本性的因素可以使该选择变得优越:Haskellers 使用的大多数函数似乎在融合的 foldr/build
模式中比在另一个。在 other places ,使用展开图案。
序言结束了,我们需要问两个问题:
head
和 iterUntilM
)是否仅在 foldr
表示(如追加)中有效工作,或者在 展开器
表示(如tail
),或两者(如map
)?foldr
?),还是可以受更多限制?head
可以很容易地在 foldr
编码列表上实现:
head xs = runList xs const (error "head: empty list")
在 foldl'
-lists 上,情况有点复杂:
head xs =
fromMaybe
(error "head: empty list")
(build xs (\xs x -> maybe (Just x) Just xs) Nothing)
您会注意到这个函数(如 foldr
-lists 上的 tail
)的复杂度为O(n)。它也不适用于无限列表。这很好地表明 foldl'
不是融合 head
的正确选择。
现在,对于iterUntilM
,我们看到了一种情况(我认为)甚至融合也是可能的。因为 m
最终位于外部,所以您必须运行列表中的所有效果(具体化它)。
有关此区域的详细概述,请查看 this博客文章。
关于list - 关于 Haskell 中的 Church 编码列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50765349/
我已经为 Javascript 中的求和类型的想法苦苦挣扎了很长一段时间。该语言既不包括本地和类型也不包括模式匹配。虽然您可以使用普通的旧 Javascript Object 和原型(prototyp
这有点深奥,但令人抓狂。在对 another question 的回答中,我注意到在这个完全有效的程序中 poo :: String -> a -> a poo _ = id qoo :: (a ->
我找不到将加法定义为重复递增的方法,尽管这在无类型语言中是可能的。这是我的代码: {-# LANGUAGE RankNTypes #-} type Church = forall a . (a ->
我试图在 Haskell 中实现 Church 数字。这是我的代码: -- Church numerals in Haskell. type Numeral a = (a -> a) -> (a ->
我对 lambda 演算中的自然数有如下定义,这是我的主要目标。 -- Apply a function n times on x apply = \f -> \n -> \x -> foldr ($
有人使用过这种编程语言吗 Church ?谁能推荐一下实际应用吗?我刚刚发现它,虽然听起来它解决了人工智能和机器学习中一些长期存在的问题,但我对此表示怀疑。我从来没有听说过它,并且惊讶地发现它实际上已
我一直在阅读的《计算机程序的结构和解释》一书通过定义零和增量函数来介绍 Church 数字 zero: λf. λx. x increment: λf. λx. f ((n f) x) 这对我来说似乎
我希望能够使用 cata来自 recursion-schemes Church 编码列表的包。 type ListC a = forall b. (a -> b -> b) -> b -> b 为方便
下面的 to_c 函数在使用我想用于此处未显示的不相关代码片段的 GADTs 扩展进行编译时由于类型错误而被拒绝。 newtype Church = Church { unC :: forall a.
我看到多次引用 Church Rosser theorem ,特别是钻石属性图,在学习函数式编程时,但我还没有遇到过很好的代码示例。 如果像 Haskell 这样的语言可以被视为一种 lambda 演
作为打发时间,我正在尝试解决我在大学上的一门类(class)(关于 Lambda 微积分和各种编程概念)中提出的各种问题。因此,我正在尝试在 OCaml 中实现 Church 数字和相关运算符(也作为
假设 true (t) 和 false (f) 定义如下: > let t = \x -> \_ -> x t :: t1 -> t -> t1 > let f = \_ -> \y -> y f :
各种优化问题,如this one ,导致了 Church 编码列表作为实现流融合的一种方式,即编译器消除中间结果(例如列表)。以下是在优化问题中成功使用的定义: {-# LANGUAGE RankNT
有没有办法使用 API 从 Google 检索 map ,以便显示带有标记的本地教堂列表? 我有基本的语法,我有一个基本的 API 帐户设置,但我不知道如何/如果我可以使用类型字段。 var mapO
这样的函数怎么写? : unWrap :: F f a -> Either a (f (F f a)) 其中 F - Church 编码的免费 monad.unWrap 如果值等于“Pure a”则返
我一直在使用 Free Control.Monad.Free 中的数据类型来自 free包裹。现在我正在尝试将其转换为使用 F在 Control.Monad.Free.Church但无法弄清楚如何映射
我正在研究 Swift 2.1 中的函数式编程,试图实现 Church encoding pair/cons函数( cons = λx λy λf f x y in untyped lambda ca
一段时间以来,我一直在为 Lambda 微积分苦苦挣扎。有很多资源可以解释如何减少嵌套的 lambda 表达式,但很少能指导我编写自己的 lambda 表达式。 我正在尝试使用纯 lambda 演算(
我必须为 > 、 , != 编者注:我认为这就是 OP 试图提出的问题: 我正在尝试使用 Church 编码在无类型 lambda 演算中实现以下操作: 大于(GT 或 >)。 小于(LT 或 、
我想实现 Church encoding of the pair在 Haskell 的多态 lambda 演算中。 在第 77 页,第 8.3.3 节 Peter Selinger's notes o
我是一名优秀的程序员,十分优秀!