Built Collection Lookups

35 views
Skip to first unread message

Liam Goodacre

unread,
Jan 28, 2012, 6:00:55 PM1/28/12
to last...@googlegroups.com
# Look up the nth element in a sequence: nth(Collection)(Index)
nth(Coll) = nth(Coll)
nth([])(Index) = nil
nth(Coll)(-Index) = nil
nth([H...T])(Index) = if Index==0 then H else nth(T)(Index-1)

# Look up a key in a map: lookup(Map)(Key)
lookup(Map) = lookup(Map)
lookup({})(Key) = nil
lookup({K:V...T})(Key) = if K==Key then V else lookup(T)(Key)

# Find an element in a collection: element(Collection)(Element)
element(Coll) = element(Coll)
element([])(Value) = nil
element([H...T])(Value) = if H==Value then H else element(T)(Value)
element({})(Value) = nil
element({K:V...T})(Value) = if V==Value then V else element(T)(Value)

Ian Clarke

unread,
Jan 28, 2012, 6:48:00 PM1/28/12
to last...@googlegroups.com
Awesome stuff :-)

Ian.

--
Ian Clarke

Liam Goodacre

unread,
Jan 28, 2012, 10:03:12 PM1/28/12
to last...@googlegroups.com
A collection of my experiments.

Fork a copy:

ID of my copy: 0b42WFX


map(Fn) = map(Fn)
map(Fn)([]) = []
map(Fn)([H...T]) = [Fn(H)...map(Fn)(T)]

reduce(Fn) = reduce(Fn)
reduce(Fn)([H...T]) = reduce(Fn)(H)(T)
reduce(Fn)(V)([]) = V
reduce(Fn)(V)([H...T]) = reduce(Fn)(Fn(V)(H))(T)

filter(Fn) = filter(Fn)
filter(Fn)([]) = []
filter(Fn)([H...T]) = if Fn(H) then [H...filter(Fn)(T)] else filter(Fn)(T)

nth(Coll) = nth(Coll)
nth([])(Index) = nil
nth(Coll)(-Index) = nil
nth([H...T])(Index) = if Index==0 then H else nth(T)(Index-1)

lookup(Map) = lookup(Map)
lookup({})(Key) = nil
lookup({K:V...T})(Key) = if K==Key then V else lookup(T)(Key)

element(Coll) = element(Coll)
element([])(Value) = nil
element([H...T])(Value) = if H==Value then H else element(T)(Value)
element({})(Value) = nil
element({K:V...T})(Value) = if V==Value then V else element(T)(Value)
head([H...T]) = H
tail([H...T]) = T

abs(A) = A
abs(-A) = A
floor(A) = int(A-0.5)

"Ratios, use as such" "1//4 + 3//4 -> 1"
X//Y = X//Y
Op X//Y = Op (X/Y)
X//Y Op = (X/Y) Op

isSeq([Head...Tail]) = true
isSeq(Other) = false

range(X)(Y) = if X<Y then [X...range(X+1)(Y)] else []
range(X) = range(0)(X)

step([]) = []
step([H...T]) = if T!=[] then [H,step(T)] else [H]

keys({}) = []
keys({K:V...T}) = [K...keys(T)]
vals({}) = []
vals({K:V...T}) = [V...vals(T)]


Ian Clarke

unread,
Jan 29, 2012, 11:17:43 AM1/29/12
to last...@googlegroups.com
Wow!

One thing, there is an aspect of the pattern matching syntax on maps that you may have missed (or, more likely, that I never explained ;).

You can define lookup as follows:

lookup A {A:V ... R} = V

Then:

lookup 1 {1:2, 5:3}

This may make it clearer what is happening:

get5andrest {5:V ... R} = V R

get5andrest {3:33, 4:44, 5:55, 6:66}

See how you can pick out a key from the map through binding, and the remaining key/values bind to R.

Ok, if all goes well today we'll have some (long overdue) documentation on the site.

Liam Goodacre

unread,
Jan 29, 2012, 11:47:52 AM1/29/12
to last...@googlegroups.com
Ah that's very interesting!

Although I can't seem to switch the values?

What I'm thinking is joining data with the function:
lookup(Data) = lookup(Data)

Then if I pass in a key, and lookup on a map:
lookup(Key)([Key:Value...Rest]) = Value

Or if I pass in a map, then lookup a key:
lookup([Key:Value...Rest])(Key) = Value

Here are my results:

v1(M) = lookup(b)(M)
v2(M) = lookup(M)(b)
v3(K) = lookup(K)({a:1, b:2, c:3})
v4(K) = lookup({a:1, b:2, c:3})(K)

v1({a:1, b:2, c:3}) -> 2 ~Expected
v2({a:1, b:2, c:3}) -> 1 ~Unexpected
v3(b) -> 2 ~Expected
v4(b) -> 1 ~Unexpected

What are your thoughts on this?

A way around this is to switch the parts to a particular order before hand:
lookup({K:V...T})(X) = lookup(X)({K:V...T})

Although this seems a little unintuitive to have to do.

Also without the searching method, you can't catch a situation when you lookup a key which doesn't exist in the map?
lookup(d)({a:1, b:2, c:3}) -> lookup d { a : 1, b : 2, c : 3 } ~What happens
lookup(d)({a:1, b:2, c:3}) -> nil ~What I'd prefer

Cheers.

Liam Goodacre

unread,
Jan 29, 2012, 11:55:17 AM1/29/12
to last...@googlegroups.com
Sorry these two lines should have had curly braces:
lookup(Key)({Key:Value...Rest}) = Value

Ian Clarke

unread,
Jan 29, 2012, 11:57:00 AM1/29/12
to last...@googlegroups.com
On Sun, Jan 29, 2012 at 10:47 AM, Liam Goodacre <goodac...@gmail.com> wrote:
Ah that's very interesting!

Although I can't seem to switch the values?

Yes, currently the variables on the left side of the function definition are "bound" from left to right, so the Key variable is "bound" to the value you pass in as the first parameter, and then it is used to retrieve the value from the map.

Also without the searching method, you can't catch a situation when you lookup a key which doesn't exist in the map?
lookup(d)({a:1, b:2, c:3}) -> lookup d { a : 1, b : 2, c : 3 } ~What happens
lookup(d)({a:1, b:2, c:3}) -> nil ~What I'd prefer

Yes, this is a valid point.  The key-binding in a map functionality was originally conceived for situations where you could be confident that the key exists.

Let me think about a better way to handle a situation where you are trying to bind to a non-existent key.

Ian.

Liam Goodacre

unread,
Jan 29, 2012, 12:08:58 PM1/29/12
to last...@googlegroups.com
I suppose it might be valid to first use something to check if the key exists in the map, before looking it up?

Something like:
inMap(D) = inMap(D)
inMap(Key)({}) = false
inMap({K:V...R})(Key) = inMap(Key)({K:V...R})
inMap(Key)({K:V...R}) = if Key==K then true else inMap(Key)(R)

But I'd think it would be situation dependant.

Ian Clarke

unread,
Jan 29, 2012, 12:15:43 PM1/29/12
to last...@googlegroups.com
On Sun, Jan 29, 2012 at 11:08 AM, Liam Goodacre <goodac...@gmail.com> wrote:
inMap(D) = inMap(D)

I'm curious, why do you do the above - it shouldn't have any effect - have you found that it does?
 
inMap(Key)({}) = false
inMap({K:V...R})(Key) = inMap(Key)({K:V...R})
inMap(Key)({K:V...R}) = if Key==K then true else inMap(Key)(R)

But I'd think it would be situation dependant.

That would work, a bit inefficient though.  I will be providing native functions to retrieve values from maps, along with all the other common collections functions that you've been implementing - so these will probably provide better ways to deal with non-existent keys.

Ian.

Liam Goodacre

unread,
Jan 29, 2012, 12:32:59 PM1/29/12
to last...@googlegroups.com
I was experiencing situations in which values weren't properly used, but it seems fine now.
It used to give strange output for something like this:
add(X)(Y) = X+Y
add10 = add(10)
map10 = map(add10)
map10([1, 2, 3, 4])

But now the final line does give me [11, 12, 13, 14].

It used to give me something like "map(add 10)([1, 2, 3, 4])" but not evaluate it.
One time I also got "map + 10 [1, 2, 3, 4]"

But yeah, it seems to be fine now.

But I do get "map(add 10)([1, 2, 3, 4])" if I enter:
map(add(10))([1, 2, 3, 4]), instead of [11, 12, 13, 14]

Ian Clarke

unread,
Jan 31, 2012, 11:15:00 AM1/31/12
to last...@googlegroups.com
On Sun, Jan 29, 2012 at 11:32 AM, Liam Goodacre <goodac...@gmail.com> wrote:
I was experiencing situations in which values weren't properly used, but it seems fine now.

FYI Liam, I think I found this intermittent bug and fixed it.
Reply all
Reply to author
Forward
0 new messages