Haskell 哈斯克尔:循环?
我是Haskell的新手,希望在Haskell中复制以下内容。接近环路的最佳方式是什么Haskell 哈斯克尔:循环?,haskell,Haskell,我是Haskell的新手,希望在Haskell中复制以下内容。接近环路的最佳方式是什么 kCenterX = kCols / 2; kCenterY = kRows / 2; for(i=0; i < rows; ++i) // rows { for(j=0; j < cols; ++j) // columns { for(m=0; m < kRows; ++m) // kernel rows
kCenterX = kCols / 2;
kCenterY = kRows / 2;
for(i=0; i < rows; ++i) // rows
{
for(j=0; j < cols; ++j) // columns
{
for(m=0; m < kRows; ++m) // kernel rows
{
mm = kRows - 1 - m; // row index of flipped kernel
for(n=0; n < kCols; ++n) // kernel columns
{
nn = kCols - 1 - n; // column index of flipped kernel
// index of input signal, used for checking boundary
ii = i + (m - kCenterY);
jj = j + (n - kCenterX);
// ignore input samples which are out of bound
if( ii >= 0 && ii < rows && jj >= 0 && jj < cols )
out[i][j] += in[ii][jj] * kernel[mm][nn];
}
}
}
}
kCenterX=kCols/2;
kcentry=kRows/2;
对于(i=0;i=0&&ii=0&&jj
因为(乍一看)您正在做一些相当棘手的索引工作,所以您可以使用命令式风格来移植它。否则,您将不得不深入研究该算法的原因,并以不同的方式表达它
这里有一个例子可以帮助你。下面的C代码(我之所以选择它,是因为它在赋值的左侧有索引数学)
void示例(常量int*输入、int大小、int*输出){
//假设输出初始化为零
对于(int i=0;i
可以从字面上翻译为Haskell,如下所示:
import Control.Monad (forM_)
import Data.Array.ST
import Data.Array
example :: Array Int Int -> Array Int Int
example input = runSTArray $ do
output <- newArray (bounds input) 0
forM_ (indices input) $ \i -> do
let newi = i `div` 2
writeArray output newi (input ! i)
return output
import-Control.Monad(表单)
导入Data.Array.ST
导入数据。数组
示例::Array Int->Array Int
示例输入=runSTArray$do
输出do
设newi=i`div`2
writeArray输出newi(输入!i)
返回输出
(尽管这与我们在惯用的Haskell中表达该函数的方式相去甚远。)
如果你对这个符号有什么特别的问题,如何扩展到多维数组,一旦你得到了纯数组,如何使用它,或者其他什么,我建议你作为一个单独的问题来问
我还要说,这项任务使用了一些更复杂的Haskell概念(主要是因为我们必须使用一些技巧来用函数式语言说祈使句),如果您是Haskell的新手,那么这可能不是最好的起点。祝你好运 在查看代码一段时间后,它似乎是一个应用具有0边界(截断访问)的卷积内核的代码。所以我的第一步是。实际上,我会选择一个使用合适数据类型的,比如版本。在这种情况下,我将把你的函数写成:
outarray = runIdentity $ convolveOutP (outAs 0) kernel inarray
其中runIdentity
来自Data.Functor.Identity,用于打开monadconvolveOutP
返回其中的数据
但实现功能,而不是找到它,完全是另一项任务。我将从一个合适的数据类型开始,例如from(Repa也使用它)。它们没有2D索引,但我们可以使用。或者已经有人帮我们做了,让我们从这个开始
首先,我们的数组索引现在不需要从零开始。所以我们可以定义一个中心为零的内核:
import Data.Array.Unboxed
kernelShape = ((-1,-1), (1,1))
-- Simple blurring kernel function for example
weight (x,y) = 2**(-2-fromIntegral (abs x)-fromIntegral (abs y))
kernel :: UArray (Int,Int) Float
kernel = listArray kernelShape [weight (x,y) | (x,y) <- range kernelShape]
-- We can check the weights add up:
one = sum $ elems kernel
import Data.Array.unbox
核形状=(-1,-1,(1,1))
--以简单模糊核函数为例
重量(x,y)=2**(-2-从积分(abs x)-从积分(abs y))
内核::UArray(Int,Int)浮点
kernel=listary kernelShape[weight(x,y)|(x,y)惯用的Haskell会以一种非常不同的方式来实现这一点。我认为你应该在Haskell中学习函数式编程的一些基本概念。如果你不习惯它,一开始会很奇怪,但在我看来,一旦你进入它,它会很有趣。通过以一种更好的方式为FP重新构造问题,事实上,它可能会变得非常简单。首先,你可能认为您必须递归地编写函数,并且您必须学会这样做,但如果问题合适,可能会有更高阶的函数使问题变得几乎微不足道。FP不是命令式概念的新语法。一般来说,您不需要在Haskell中重写代码。您只需从描述开始在Haskell中编写代码说明输入和输出是什么以及它们是如何关联的,而不是从描述你将如何用另一种语言做某事开始。因为(一目了然)你正在做一些相当棘手的索引工作,你可以使用命令式风格来移植它。否则你必须深入研究算法的原因,并用不同的方式表达它。“请为我翻译这段代码”是学习新习语的糟糕方法。我建议你尝试学习Haskell,在遇到困难时急切地问问题。像这里所做的那样,不带方向地问一个广泛的问题并不是学习这门语言的有效方法。像linear
这样的库可能会有所帮助。
import Data.Array.Unboxed
kernelShape = ((-1,-1), (1,1))
-- Simple blurring kernel function for example
weight (x,y) = 2**(-2-fromIntegral (abs x)-fromIntegral (abs y))
kernel :: UArray (Int,Int) Float
kernel = listArray kernelShape [weight (x,y) | (x,y) <- range kernelShape]
-- We can check the weights add up:
one = sum $ elems kernel
convolve kernel inA = accumArray (+) 0 (bounds inA) placedterms
where placedterms = [((x,y), (kernel!(lx,ly)) * (inA!(x+lx,y+ly))) |
(x,y) <- indices inA,
(lx,ly) <- indices kernel,
inRange (bounds inA) ((x+lx),(y+ly))]
convolvedkernel = convolve kernel kernel :: UArray (Int,Int) Float