我正在尝试编写C#版本(以C#样式)的F# reduce函数,如下所示:
https://github.com/quantalea/AleaGPUTutorial/tree/master/src/fsharp/examples/generic_reduce
更具体地说,以下面的函数为例:
let multiReduce (opExpr:Expr<'T -> 'T -> 'T>) numWarps =
let warpStride = WARP_SIZE + WARP_SIZE / 2 + 1
let sharedSize = numwarps * warpStride
<@ fun tid (x:'T) ->
// stuff
@>我主要是一个F#的人,我不太确定我应该如何在C#中编写这样的函数。对于C#版本,multiReduce函数将是类成员。因此,如果我想对F#代码进行更直接的转换,我会从我的MultiReduce成员返回一个函数。
另一种选择是“扁平化”multiReduce函数,这样我的C#成员版本就会有两个额外的参数。所以..。
public T MultiReduce(Func<T,T,T> op, int numWarps, int tid, T x)
{
// stuff
}但我不认为这在所有情况下都适用于AleaGPU编码,因为在F#版本中引用的表达式是一个设备函数。您需要嵌套的函数结构能够将某些变量的赋值与函数的实际调用分开。
我看到的另一种方法是创建一个MultiReduce类,并将opExpr和numWarps作为字段,然后使引用中的函数成为类成员。
那么在AleaGPU-C#中,像这样的高阶函数通常是如何实现的呢?我不认为在任何地方都返回Func<..>是好的,因为我在C#编码中看不到太多这样做。AleaGPU是一种特殊情况,在这种情况下可以吗?
基本的AleaGPU C#实现如下所示:
internal class TransformModule<T> : ILGPUModule
{
private readonly Func<T, T> op;
public TransformModule(GPUModuleTarget target, Func<T, T> opFunc)
: base(target)
{
op = opFunc;
}
[Kernel]
public void Kernel(int n, deviceptr<T> x, deviceptr<T> y)
{
var start = blockIdx.x * blockDim.x + threadIdx.x;
var stride = gridDim.x * blockDim.x;
for (var i = start; i < n; i += stride)
y[i] = op(x[i]);
}
public void Apply(int n, deviceptr<T> x, deviceptr<T> y)
{
const int blockSize = 256;
var numSm = this.GPUWorker.Device.Attributes.MULTIPROCESSOR_COUNT;
var gridSize = Math.Min(16 * numSm, Common.divup(n, blockSize));
var lp = new LaunchParam(gridSize, blockSize);
GPULaunch(Kernel, lp, n, x, y);
}
public T[] Apply(T[] x)
{
using (var dx = GPUWorker.Malloc(x))
using (var dy = GPUWorker.Malloc<T>(x.Length))
{
Apply(x.Length, dx.Ptr, dy.Ptr);
return dy.Gather();
}
}
}发布于 2015-03-25 06:00:58
高阶函数在C#中并不像在F#中那么普遍。虽然有很多接受函数作为参数的示例,但C#代码很少将函数作为结果返回。我猜这部分是因为代码非常难看(到处都是Func<T,U>),还有一部分原因是C#程序员通常不习惯函数式风格,更倾向于面向对象的方式。
特别是,在C#中没有自动货币/部分应用程序。你可以把它想象成所有的F#函数都有元组参数。实际上,如果从F#调用多参数C#方法,它看起来就是这样的。
我还必须指出,您代码中的函数实际上并不是“高阶”的。它既不接受也不返回任何函数。相反,它接受并返回报价,这完全不是一回事。粗略地说,函数是对一段代码的引用,而quotation是一种数据结构。它们看起来很相似,但它们是完全不同的动物。
C#也有自己的引用,由类型System.Linq.Expressions.Expression<T>表示(其中T必须是委托类型)。然而,它们与F#报价不是一回事。在F#方面,您可以(某种程度上)使用C# quotation,但反之亦然。
F#和C#报价各有长处和短处。特别是,C#支持编译,F#不支持;F#支持拼接,C#不支持。
这就引出了我的下一点:你可能需要拼接。因为您在返回的引用的正文中使用了opExpr,不是吗?
而且C#对它没有开箱即用的支持。是的,理论上可以将拼接实现为库函数,但由于某些原因,没有事实上的标准,没有定期维护的实现。我们,其中之一,不得不推出我们自己的。它也是开源的,而且非常简单,所以feel free to use it。
现在,说完上面的所有内容,我想表达一个疑问,您是否能够使用C#来实现这一点。我真的不知道GPU是如何工作的,但它看起来像是希望你返回一个F#引用,然后它可能会将其编译成AleaGPU代码。如果是这样的话,因为C#和F#报价是两个不同的东西,所以您可能无法向AleaGPU返回C#报价,而不是返回F#报价。当然,除非它有单独的支持。
https://stackoverflow.com/questions/29238031
复制相似问题