NAME
Junc.pod - explanation of how Junc.hs works
OVERVIEW
I am a fledgling Haskell programmer having just finished reading YAHT. For some reason, I was attracted to understanding Junc.hs and so will document its workings.
Junc.hs is the main code for implementing Perl6 Junctions:
http://dev.perl.org/perl6/synopsis/S09.html
HOW THE MODULE WORKS
First we load in the Internals
and the abstract syntax tree, AST
.
The first thing to understand is how opJunc
works. It's just the first function in the file, but it is important, so let's get down to business.
opJunc
The type signature of this function is
opJunc :: JuncType -> [Val] -> Val
which means it takes a JuncType
and a list of type Val
and returns an element of type Val
. More properly this function returns an element of type VJunc, but you cannot specify that a function returns a subtype only a type.
Here is it's definition. Let's understand it:
opJunc :: JuncType -> [Val] -> Val
opJunc t vals = VJunc $ Junc t emptySet (joined `union` mkSet vs)
where
joined = unionManySets $ map (\(VJunc s) -> juncSet s) js
(js, vs) = partition sameType vals
sameType (VJunc (Junc t' _ _)) = t == t'
sameType _ = False
sameType and partition
js
and vs
are defined by a call to partition
, which takes a list of elements and returns a list in which the first list is those elements which satisfied a predicate and the second list is those which failed. So, js
turns out to be all elements which are the same as the type we passed in and vs
are the ones which are not the same type. How does sameType
work? The call to sameType is using pattern matching. VJunc
, if you look in AST.hs, is part of some punnery being used in the Val
enumerated set type. VJunc is both a data constructor and it receives a parameter of type VJunc which is defined further down. Pattern matching the first element of a value of type VJunc extracts the type of the VJunct. If the two types are equal, then we have the same type.
So now we understand 75% of the where
clauses for opJunc
. Now for 100% closure on where
let's understand joined
:
joined
joined = unionManySets $ map (\(VJunc s) -> juncSet s) js
Well, we know that js
is the list of values that are the same type of as the passed-in type. Now, this function:
(\(VJunc s) -> juncSet s)
might look a little funny but it's simple. We are pulling the juncSet
slot from a value (namely s) whose type is VJunct. In Perl5 you might do $s->{juncSet} for the same effect.
So, all the map is doing is extracting the juncSet
fields from a list of values of type VJunc
. Then this list is passed to unionManySets
:
http://www.haskell.org/ghc/docs/5.04.3/html/base/Data.Set.html#unionManySets
which takes a list of Sets and turns them into a single set.
Now that we know what each of the where
clauses does for the main clause, let's understand the main clause:
opJunc t vals = VJunc $ Junc t emptySet (joined `union` mkSet vs)
in the context of a real call to it:
opJuncAll = opJunc JAll
isTotalJunc, isPartialJunc (in the context of ApplyArg)
Both isTotalJunc
and isPartialJunc
operate on a single piece of data of type ApplyArg
. The ApplyArg
value slot must be of type VJunc
or either function will return False.
isTotalJunc
tests to see if the VJunc value slot is of type JAll
or JNone
. Note that unlike most tests which return True
if their test passes, this function (and isPartialJunc
) return the negation of the argCollapsed
slot.
isPartialJunc
tests to see if the VJunc value slot is of type JOne
or JAny
. It also returns the negation of the argCollapsed
slot if this test passes and False otherwise.
TODO
errata
20:58] <autrijus> it will take some used to at first [20:58] <autrijus> but the context will make it clear [20:58] <autrijus> cool with it? [20:59] <autrijus> juncSet is used for all junctions [20:59] <metaperl> yes [20:59] <autrijus> juncDup is only used for none() [20:59] <autrijus> the reason is that none() cannot be represent as one set [20:59] <autrijus> must use two sets.
argsCollapsed
AUTHOR
metaperl with help from Cale, Igloo