我觉得TVar很容易使用,即使MVar看起来更简单一些,而TVar更有特色.
所以我的问题很简单,我想要什么条件去MVar而不是TVar?我想任何时候我都不需要事务更新我可以使用一个MVar,但这对我有什么好处?
TL;博士;
在C#中,你是否保证一个懒惰的迭代器函数只调用它本身并且有一个有效的递归退出条件不会导致堆栈溢出?
详细问题:
我知道通常你不能保证由C#编译器(或JIT)生成的尾调用优化(TCO)指令,所以虽然你可能得到TCO,但是没有保证.
鉴于TCO的这种认识,我想知道懒惰的迭代器函数(使用yield return等)是否因为它们作为协程的性质 - 每个尾部调用一个甚至占用堆栈空间?由于它们的重新进入,我对协同程序的直觉是默认情况下每个尾调用都被优化为跳出函数并从父框架跳到下一个函数而不是创建新框架的能力似乎很自然.
这是C#中的行为,还是C#迭代器函数的递归调用是从当前创建一个新帧而不是弹出到父帧并使用新参数重新输入?
例:
public static IEnumerable<IEnumerable<T>> GeneratePermutations<T>(this IEnumerable<T> choices, int numberToChoose)
{
if (numberToChoose == 1)
{
foreach (var choice in choices)
yield return new T[] { choice };
yield break;
}
var subPermutations = choices.SelectMany(choice =>
choices.Where(elem => !EqualityComparer<T>.Default.Equals(elem, choice))
.GeneratePermutations(numberToChoose - 1)
.Select(permutation => (new T[] { choice }).Concat(permutation)));
foreach (var perm in subPermutations)
yield return perm;
}
Run Code Online (Sandbox Code Playgroud)
我的直觉基于上面的例子subPermutations只是一个堆积的计算,它似乎在调用迭代它,它可以知道它是一个堆积的计算(它是函数sig的一部分,它是一个迭代器函数),因此立即跳转超出它的当前帧并将堆积的计算扩展到一个新的帧 - 在尝试递归调用 …
我如何干净利落地在F#中使用它?
add 1 2 x = 3 + x
add 1 x y = 1 + x + y
add z x y = z + x + y
Run Code Online (Sandbox Code Playgroud) 我有两个问题,源于观察到的C#静态方法的行为(我可能会误解):
第一:递归静态方法在某种意义上是通过静态方法在封面下实现的方式进行尾调用优化吗?
第二:使用静态方法编写整个应用程序并且没有超出局部范围的变量,它是否等同于函数式编程?我很想知道,因为我仍然没有把这个"没有副作用"的术语包围起来,我一直听说功能性编程.
编辑:让我提一下,我确实使用并理解为什么以及何时在正常的C#OO方法中使用静态方法,并且我确实理解尾部调用优化不会明确地对递归静态方法进行.也就是说,我理解尾部调用优化是尝试在每次传递时停止创建新的堆栈帧,并且我在几个点观察到在它的调用方法的框架内执行的似乎是一个静态方法,尽管我可能误解了我的观察.
来自Haskell玩氮气并遇到一些我无法找到的例子,所以如果有人可以帮助我:
在erlang中Haskell的位置(以及或者是否允许或任何类型的函数嵌套以访问父变量)?怎么样?你能?
burnOrDie hotness = foldl1 (>>) $ map burn ["Jimmy", "Adam", "Gonzo"]
where burn x
| hotness < 3 = print $ x ++ ": Ouch!"
| otherwise = print $ x ++ ": GAHHH! *die*"
Run Code Online (Sandbox Code Playgroud)
部分申请?哈斯克尔:addOne = +1
在线lambda函数?哈斯克尔:map (\x -> x+x) [1,2,3]
我发现很多东西我自己一起跳起来似乎完全有用,实际上有一个我不知道的标准实现,所以很奇怪,如果有人可以说他们已经看过这种类型的东西之前使用过:
它需要一个monadic函数并将折叠它,直到通过替代选择谓词然后它返回谓词的结果:
until :: (Monad m, Alternative m) => (a -> m a) -> (a -> m c) -> a -> m c
f `until` p = \a -> (f >=> (p `altF` (until f p))) a
where f1 `altF` f2 = \a -> f1 a <|> f2 a
Run Code Online (Sandbox Code Playgroud)
我意识到这个名字是一个前奏冲突,我可能会把它命名为别的,但我想我先看看在标准库中是否已经有类似的功能,我只是不知道...
另外我想我很好奇,如果我写的组合替代方案是在其他地方定义的,或者如果这些功能中的任何一个看起来都是错误的.但问题的关键在于,这是在其他地方实施的,还是在其他地方实施的非常相似的事情
我认为这不能称为"定点递归",因为它太简单了.但是,我最近意识到它实际上可能是.
我有效地实现了定点递归吗?
这是有问题的功能:
/* recursive kleisli fold */
var until = function(f) {
return function(a) {
return kleisli(f, until(f))(a);
};
};
Run Code Online (Sandbox Code Playgroud)
这是一些额外的背景:
// The error monad's bind
var bind_ = function(f, m) { return m.m === Success ? f(m.a) : m; };
var bind = function(f, m) {
return m !== undefined && m.m !== undefined && m.a !== undefined ? bind_(f, m) : m;
};
var kleisli = function(f1, f2) {
return function(a) {
return bind(f2, f1(a));
};
}; …Run Code Online (Sandbox Code Playgroud) 我看到有些人倾向于将方法交给回调/事件,然后有时只是把他们交给lambdas.
谁能说出两者之间的差异?我原本以为它们是相同的,但是我所看到的不一致有时让我想知道是否有一个比另一个更好的情况?显然,如果有大量代码,它不应该是现场lambda,否则..
您是否可以概述两者之间的任何差异(如果有),并概述您在两者可用时选择的规则?
我怎么做F#中的haskell:
f acc (x:y:z:xs) = f (acc-x+y*z) xs
f acc [] = acc
Run Code Online (Sandbox Code Playgroud)
算法有任意性,重要的一点是选择列表的前3个和尾部,因为我需要使用它们的全部和尾部.
我是否必须在F#中使用重复的头部调用强制编写它以弹出xy和z?
编辑:请评论这项技术在haskell中正式调用的内容,我将把它放在其他人未来搜索的问题标题中,我不记得它.
我写了一个快速的attoparsec解析器来遍历一个aspx文件并删除所有的样式属性,它的工作正常,除了它的一部分,我无法弄清楚如何使它成功匹配>而不消耗它.
这就是我所拥有的:
anyTill = manyTill anyChar
anyBetween start end = start *> anyTill end
styleWithQuotes = anyBetween (stringCI "style=\"") (stringCI "\"")
styleWithoutQuotes = anyBetween (stringCI "style=") (stringCI " " <|> ">")
everythingButStyles = manyTill anyChar (styleWithQuotes <|> styleWithoutQuotes) <|> many1 anyChar
Run Code Online (Sandbox Code Playgroud)
我理解这部分是因为我在everythingButStyles中如何使用manyTill,这就是我如何积极地放弃所有样式的东西,但是styleWithoutQuotes我需要它来匹配">"作为结束,但不要消耗它,在parsec中我会做,lookAhead ">"但我不能在attoparsec做到这一点.
haskell ×6
.net ×4
c# ×3
f# ×2
attoparsec ×1
combinators ×1
delegates ×1
erlang ×1
javascript ×1
lambda ×1
monads ×1
parsing ×1
static ×1
stm ×1
syntax ×1
yield-return ×1