Talk:Grok Functionals
From Nemerle Homepage
i tried writing some hofs using nemerle. is this the best way do write them?
def compose(f,g) {
def h(y) { f(g(y)) }
h //this is awkward syntax
}
def curry(f,x) {
def g(y) {
f(x,y)
}
g
}
def inc(i) {
i + 1
}
def twice(f,x) {
def g = compose(f, f);
g(x);
}
def tw = curry(twice, inc);
print("twice: $(tw(1))\n");
def foldr(f,l,z) {
match(l) {
|[] => z
|h::t => f(h,foldr(f,t,z))
}
}
print("foldr: $(foldr(_+_,[1,2,3],0))\n");
def zip(f,a,b) {
match((a,b)) {
|([],_) => []
|(_,[]) => []
|(ah::at,bh::bt) => f(ah,bh)::zip(f,at,bt)
}
}
print("zip: $(zip(_+_,[1,2,3],[4,5,6]))\n");
def map(f,lst) {
match(lst) {
|[] => []
|h::t => f(h)::map(f,t)
}
}
print("map: $(map(inc,[1,2,3]))\n");
any idea why this map doesnt work?
def map2(f,lst) {
def g(x,y) {
f(x)::y;
}
foldr(g, lst, []);
}
print("map2: $(map2(inc,[1,2,3]))");
Instead of:
def compose(f,g) { def h(y) { f(g(y)) } h //this is awkward syntax }
you can use:
def compose(f,g) { fun (y) { f(g(y)) } }
which isn't as bad.
Same with curry.
Otherwise it seems OK. The second map doesn't work because the foldr you defined is not polymorphic. Nemerle does not infer polymorphic types. Please refere to this message for details.
--Malekith 10:06, 14 Oct 2005 (CEST)
how would i define a foldr thats polymorphic? or how would i define foldr that can be used to define map, and used to sum the list?
def foldr ['a] (f,l : list ['a],z) {
match(l) {
|[] => z
|h::t => f(h,foldr(f,t,z))
}
}
Just a small hint for compiler on l parameter.
--Nazgul 22:39, 14 Oct 2005 (CEST)
i still get this error in my map2 function
def foldr['a](f, l : list['a], z) { match(l) { |[] => z |h::t => f(h,foldr(f,t,z)) } } def map2(h, l) { def g(x, y) { h(x)::y; } foldr(g, l, []); } print("map2: $(map2(inc,[1,2,3]))"); test.n:54:4:54:9: error: in argument #1 (f), needed a (System.Object+ * int-) -> int+, got (? * list[System.Object+]+) -> list.Cons[System.Object+]-: types int and list[System.Object+] are not compatible [during intersection] test.n:54:4:54:9: error: typing error in call
so why does it think that f is getting a list instead of an int. map2 seems to work fine with the default foldright.
def inc(x) { x + 1 } def foldr['a](f, l : list['a], z) { match(l) { |[] => z |h::t => f(h,foldr(f,t,z)) } } def map2(h, l) { def g(x, y) { h(x)::y; } foldr(g, l, []); } System.Console.WriteLine ($ "map2: $(map2(inc,[1,2,3]))");
--Malekith 19:10, 15 Oct 2005 (CEST) This works for me:
that breaks if you use foldr initially with a different type
print("foldr: $(foldr(_+_,[1,2,3],0))\n"); print("map2: $(map2(inc,[1,2,3]))\n");
based on what malekith said on irc i think this should work for all cases
def foldr['a, 'b](f : 'a * 'b -> 'b, l, z : 'b) { match(l) { |[] => z |h::t => f(h,foldr(f,t,z)) } }
seems to me that thats a bug in the compiler. i dont think the order in which a function is used should define its type, or the function type shouldn't depend on the order in which its used.
But they do. I consider it a feature not a bug. This is described in more detail in the page about type inference, though this page still isn't complete. This dependence is there to solve ambigious member access problem, which is far more common in Nemerle than polymorphic local functions.
Still it may be possible to infer polymorphic types, but this requires more theoretical (and probably implementation) work.
--Malekith 22:40, 15 Oct 2005 (CEST)
so you are saying how a function is used changes its definition? i don't think that should be legal. there could be no way for me to know what code is run before any my code, and that code shouldn't be able to change the interfaces that i am using.
class Foo { my_value : int; public Barize () : void { System.Console.Write ($ "Foo ($my_value), " "times 42 = $(my_value * 42)\n"); } } class Qux { public Barize () : void { } } def call_barize (x) { x.Barize () } def our_list = [Foo (1), Foo (2), Foo (3)]; foreach (e in our_list) call_barize (e);
How would you type call_barize here, if there was no use of it? And we really would like to avoid the type annotation in this case.
As for the interfaces, type inference is not (and WILL BE NOT) supported for public functions, exactly for the reason you mentioned. Currently even private global ones are not supported.
Principal types are a nice property, but I'm affraid impossible to hold in such a crazy type system as .net one.
--Malekith 09:56, 16 Oct 2005 (CEST)
I think I understand what is going on. I was expecting this type inference work like c++ templates, where each function is generated for each type thats its used with. but it looks like type inference in nemerle just tries to figure out what the user wanted the function type to be, and assigns that type to the function.
Exactly. --Malekith 09:14, 19 Oct 2005 (CEST)
Tuples not yet introduced
You write: "Types of functions taking more than one argument are represented as tuples. For example, the following function:"
but you have not yet introduced to the reader of the "grokking..." series what a tuple is. In fact, I was going to just link the word tuple to tuple, but it's nonexistant.
I have no idea how I'd represent a function that needed a signature of "int * string * Foo -> float", because you haven't given me any examples. --Llimllib 08:38, 14 August 2006 (CEST)
Tuples are (somehow) explained here: Grok_Various_data_structures
There is example with "some_function" above though.
Anyway I suggest you take the OOP course, as it is more complete. We should some day do something with this documentation mess...
--Malekith 11:08, 15 August 2006 (CEST)