有没有办法通过高阶函数"包装"递归函数,以便递归调用也被包装?(例如,在每次调用时记录函数的参数.)
例如,假设我们有一个函数,sum()它通过将头部添加到尾部的总和来返回数字列表的总和:
function sum(a) {
if (a.length === 0) {
return 0;
} else {
return a[0] + sum(a.slice(1));
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法编写一个高阶函数,logging()它将sum()函数作为输入,并返回一个函数,sum()在每次递归调用时输出参数?
以下不起作用:
function logging(fn) {
return function(a) {
console.log(a);
return fn(a);
}
}
sum2 = logging(sum);
sum2([1, 2, 3]);
Run Code Online (Sandbox Code Playgroud)
实际产量:
[1, 2, 3]
-> 6
Run Code Online (Sandbox Code Playgroud)
预期产量:
[1, 2, 3]
[2, 3]
[3]
[]
-> 6
Run Code Online (Sandbox Code Playgroud)
这是否sum()可以重写,以便它可以与Y Combinator风格的"递归"一起使用?
function sum_core(g) {
return function (a) {
if (a.length === 0) { …Run Code Online (Sandbox Code Playgroud) 下面是一个名为functionA的高阶函数示例,它将customValue作为输入,并返回一个获取输入并使用自定义值来详细说明结果的函数:
let functionA = (customValue) => {
let value = customValue || 1;
return input => input * value;
};
Run Code Online (Sandbox Code Playgroud)
这是一些结果:
functionA()(4)
// => returns 4
functionA(2)(4)
// => returns 8
functionA(3)(4)
// => returns 12
functionA(4)(4)
// => returns 16
Run Code Online (Sandbox Code Playgroud)
功能A返回的功能可以被认为是纯粹的吗?
更新:以上示例仅使用数字输入.正如@CRice所描述的那样,只有当customValue是常量且没有内部状态(如类)时,返回的函数才能被认为是纯函数.
在我看来,你总是可以传递函数参数而不是使用类型类。例如,而不是定义相等类型类:
class Eq a where
(==) :: a -> a -> Bool
Run Code Online (Sandbox Code Playgroud)
并在其他函数中使用它来指示类型参数必须是 的实例Eq:
elem :: (Eq a) => a -> [a] -> Bool
Run Code Online (Sandbox Code Playgroud)
我们不能只定义我们的elem函数而不使用类型类,而是传递一个函数参数来完成这项工作吗?
我正在尝试构造一个类型的函数:
liftSumthing :: ((a -> m b) -> m b) -> (a -> t m b) -> t m b
Run Code Online (Sandbox Code Playgroud)
tmonad变压器在哪里?具体来说,我有兴趣这样做:
liftSumthingIO :: MonadIO m => ((a -> IO b) -> IO b) -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)
我摆弄了一些Haskell巫术库,但无济于事.我如何做到正确,或者在某个我找不到的地方有一个现成的解决方案?
C++标准库函数按值获取functor(函数指针或函数对象)参数,如下所示:
template <typename F>
void apply(F func)
{
func();
}
Run Code Online (Sandbox Code Playgroud)
......但是通过Universal Reference传递仿函数会不会更好?像这样:
template <typename F>
void apply(F&& func)
{
func();
}
Run Code Online (Sandbox Code Playgroud)
这样,您可以传递维护状态的函数对象,并在返回高阶函数后访问该(可能已修改的)状态.
我正在阅读Eloquent JavaScript(新版本),并且我在更高阶函数上达成了一部分,我对以下代码中发生的事情感到困惑.
function noisy(f) {
return function(arg) {
console.log("calling with", arg);
var val = f(arg);
console.log("called with", arg, "- got", val);
return val;
};
}
noisy(Boolean)(0);
// ? calling with 0
// ? called with 0 - got false
Run Code Online (Sandbox Code Playgroud)
为什么这个函数的调用会像这样嘈杂?(布尔)是演员吗?为什么演员?返回值?还是论点?为什么不(布尔值)嘈杂(0)如果它的返回值.或者噪声((布尔值)0)如果参数是被转换的参数.
noisy(Boolean)(0)
Run Code Online (Sandbox Code Playgroud)这一行发生了什么?f()甚至定义在哪里?
var val = f(arg);
Run Code Online (Sandbox Code Playgroud)是否有一种"适当的"方式在C中实现更高阶的函数.
我对这里的可移植性和语法正确性等问题非常好奇,如果有多种方法,那么优点和缺点是什么.
编辑:我想知道如何创建更高阶函数的原因是我编写了一个系统来将PyObject列表(在调用python脚本时得到)转换为包含相同数据但以非方式组织的C结构列表依赖于python.h库.所以我的计划是有一个函数,它遍历pythonic列表并在列表中的每个项目上调用一个函数,并将结果放在一个列表中然后返回.
所以这基本上是我的计划:
typedef gpointer (converter_func_type)(PyObject *)
gpointer converter_function(PyObject *obj)
{
// do som stuff and return a struct cast into a gpointer (which is a void *)
}
GList *pylist_to_clist(PyObject *obj, converter_func_type f)
{
GList *some_glist;
for each item in obj
{
some_glist = g_list_append(some_glist, f(item));
}
return some_glist;
}
void some_function_that_executes_a_python_script(void)
{
PyObject *result = python stuff that returns a list;
GList *clist = pylist_to_clist(result, converter_function);
}
Run Code Online (Sandbox Code Playgroud)
并澄清问题:我想知道如何以更安全和更正确的方式做到这一点.我真的想保持更高阶的功能风格,但如果这是不赞成的话,我非常感谢以其他方式做到这一点.
更新:如果这个方法不是线程安全的,这是可以接受的,但我有兴趣学习如何使它保持线程安全.另外,key如果我可以避免它,我不想锁定所有值的单个对象.
原始问题:假设我想编写一个带有键和函数的高阶函数,并检查对象是否已使用给定的密钥进行高速缓存.如果是,则返回缓存的值.否则,运行给定的函数并缓存并返回结果.
这是我的代码的简化版本:
public static T CheckCache<T>(string key, Func<T> fn, DateTime expires)
{
object cache = HttpContext.Current.Cache.Get(key);
//clearly not thread safe, two threads could both evaluate the below condition as true
//what can I lock on since the value of "key" may not be known at compile time?
if (cache == null)
{
T result = fn();
HttpContext.Current.Cache.Insert(key, result, null, expires, Cache.NoSlidingExpiration);
return result;
}
else
return (T)cache;
}
Run Code Online (Sandbox Code Playgroud)
另外,假设我key在编译时不知道所有可能的值.
如何使这个线程安全?我知道我需要在这里引入锁定,以防止1+线程将我的条件评估为真,但我不知道要锁定什么.我读过的许多关于锁定的例子(例如Jon Skeet的文章)建议使用仅用于锁定的"虚拟"私有变量.在这种情况下,这是不可能的,因为密钥在编译时是未知的.我知道我可以通过为每个人使用相同的锁来轻松地使这个线程安全 …
现在每个人都试图使用这些高阶函数来通过编写更少的代码来获得有希望的结果。但我想知道这些功能在内部是如何工作的。
假设我写了类似的东西
var numbers = [16, 25, 36];
var results = numbers.map(Math.sqrt);
console.log(results); // [4, 5, 6]Run Code Online (Sandbox Code Playgroud)
我知道 'number' 数组的每个元素都在一个一个地迭代,但是如何?
我试图搜索它,但我还没有得到任何满意的答案。
我有一个代数数据类型,其中一些构造函数具有可比较的值,而一些构造函数则没有.我写了一些像标准(==)和(/=)运算符一样工作的比较函数,但返回Nothing没有意义的比较:
data Variant = IntValue Int
| FloatValue Float
| NoValue
equal :: Variant -> Variant -> Maybe Bool
equal (IntValue a) (IntValue b) = Just (a == b)
equal (FloatValue a) (FloatValue b) = Just (a == b)
equal _ _ = Nothing
unequal :: Variant -> Variant -> Maybe Bool
unequal (IntValue a) (IntValue b) = Just (a /= b)
unequal (FloatValue a) (FloatValue b) = Just (a /= b)
unequal _ …Run Code Online (Sandbox Code Playgroud) javascript ×4
haskell ×3
c ×1
c# ×1
c++ ×1
c++11 ×1
dictionary ×1
function ×1
functor ×1
lifting ×1
locking ×1
node.js ×1
polymorphism ×1
recursion ×1
types ×1
y-combinator ×1