Can one put a proc inside an array? This, obviously, does not work.
var arr : array[1, float]
arr[0] = (proc(x:float):float=(x*2.0))
But if it can be done, does it solve my "problem"?
To get a bit more understanding of Nim I'm converting a curve interpolation library written for POV-Ray. http://news.povray.org/povray.binaries.scene-files/attachment/%3CXnsAD34A6FC6BEB5seed7%40news.povray.org%3E/curve.inc.txt
In POV-Ray I had to put all info regarding the curve in an array, there where no dictionaries at the time. Two curve definition examples:
//CatmullRom curve
#declare _CIdef[_ci_catmul] = array[3]{
array[3]{4, 1, 2}, //dimseg, step, end
array[1]{2}, //div
array[4]{ //matrix
array[4]{-1, 3,-3, 1},
array[4]{ 2,-5, 4,-1},
array[3]{-1, 0, 1},
array[2]{ 0, 2}
}
};
#macro CIcatmul(CIarr)
_CIinit(CIarr, _ci_catmul, _CIdef[_ci_catmul])
#end
//Simple Cubic End point Slope Control
#declare _CIdef[_ci_simple3_esc] = array[3]{
array[3]{2, 1, 1}, //dimseg, step, end
array[1]{1}, //div
array[4]{ //matrix
array[2]{
function(ESC){2-(2*ESC)},
function(ESC){(2*ESC)-2}
},
array[2]{
function(ESC){(3*ESC)-3},
function(ESC){3-(3*ESC)}
},
array[2]{
function(ESC){-ESC},
function(ESC){ESC}
},
array[1]{
function(ESC){1}
}
}
};
#macro CIsimple3ESC(CIarr, ESC)
#local Type = _ci_simple3_esc;
#local Def = _CIoneVar(Type, ESC) //calculates the matrix values
_CIinit(CIarr, Type, Def)
#end
The first part of a curve definition can go into an object, but I'm struggling with the matrix part. Not only can it contain functions (procs), also the amount of entries varies and the length of the entries vary.
type
Matrix = object
matrix: ....
Curve = object
#curve_type: string
dim_seg: int
step: int
end_at: int
divisor: float
matrix: Matrix
A nudge in the right direction would be welcome.
You can definitely put procedures into an array:
var arr: array[1, proc(x: float): float]
arr[0] = proc(x: float): float = (x*2.0)
echo arr[0](100)
Whether or not it'll help you I'm not sure.. I think there is a better way to do what you're trying to do, but I haven't given it much thought.
Ah, thanks. After doing the same in an object definition that put me on the right track I think. It is not what I was looking for. The functions should not be part of the object but are just needed to initialise it. I'll fiddle a bit more with it.
Thanks.
you don't need an array of function types, all those functions are compile time. the interface for allowing a user to define a curve type, and the resulting data type that actually gets used are different problems.
for the interface, you need to replace the pov dsl with one using nim macros, which can accept something like:
CI_define(ci_catmul):
([4,1,2],
[2],
([-1,3,3,-1],
[2,-5,4,-1],
[-1,0,1],
[0,2]))
CI_define(ci_simple3_esc,esc):
([2,1,1],
[1],
([2-2*esc,2*esc-2],
[3*esc-3,3-3*esc],
[-esc,esc],
[esc]))
where CI_define is a macro that transforms the definition into, say,
type arr[x:static int] = array[x,int]
type ci_simple3 = (arr[3],arr[1],(arr[2],arr[2],arr[2],arr[1]))
proc initci_simple3(esc: int):ci_simple3 =
([2,1,1],
[1],
([2-2*esc,2*esc-2],
[3*esc-3,3-3*esc],
[-esc,esc],
[esc]))
i don't know how expressive you need that dsl to be, but for this simple example you can see the macro basically copy-pastes the body into the init proc and calculates a type based on that body.
there might be a clever way to inject the arguments into the body to get Nim to make the type for you, but worst case you can just walk the tree and replace par with tuple and bracket with array[bracket.len,int]
as for the type of Matrix, since it can be completely arbitrary, i don't see how it can be much more tightly specified than as the typeclass tuple. perhaps with old-school concepts you could check that every leaf type is int, but thats about it, and would probably explode the length of your compile times.
The more complex ones have 6 variables per proc and need some pre processing to get those variables. One has a proc for the divisor. But, looking at it all I could just as well create a proc for initialisation of the curve (pre)process all the procs needed to get the matrix values and returns an object:
Curve = object
#curve_type: string
dim_seg: int
step: int
end_at: int
divisor: float
matrix: seq[seq[float]]
pointarray: seq[seq[vec]]
proc init_simple3ESC(pointarray, esc):Curve=
var curve = Curve()
curve.dim_seg = 1
curve.... etc
process procs here to obtain matrix data
...
return curve
c = init_simple3ESC(pointarray, 2)
p = getPoint(c, 0.8)
A bit more typing but nicely explicit.
Thanks, I'll look into the macro solution.
i see, i was grossly overestimating the scope of your problem, somehow i made up in my head that you were porting the pov-ray language to nim, when you were clearly just porting one library. i feel foolish.
the macro solution is probably only worth the effort if you wanted to provide an api to extend the library, you're right that just typing it all out is no more work, especially if you type Curve the way you have done.
but on the theme of overcomplicating things, you don't need to jump through all the ridiculous hoops that are being done in this file, because you're using a real programming language.
take the example you highlighted: ci_beta
it is pretty complex, but only because it's wrestling with an underpowered templating language. If you look at the _CIdefDefDiv/_CItwoVarDiv macros, all they are doing is evaluating those functions back into the divisor and matrix respectively.
so you don't need to mess around with any of that stuff!