Author image ☻ 唐鳳 ☺
and 1 contributors


Junc.pod - explanation of how Junc.hs works


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 Perl 6 Junctions:


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.


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)
    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 pair of lists 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 = 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:

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.



[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 one() [20:59] <autrijus> the reason is that one() cannot be represent as one set [20:59] <autrijus> must use two sets.

* autrijus said none() originally, but it should be one().



metaperl with help from Cale, Igloo