`--show-options`

flag that lists all command-line flags. This feature can be used to auto-complete command-line flags in shells that support this feature. To enable auto-completion in Bash add this code snippet to your ~/.bashrc file:
# Autocomplete GHC commands _ghc() { local envs=`ghc --show-options` # get the word currently being completed local cur=${COMP_WORDS[$COMP_CWORD]} # the resulting completions should be put into this array COMPREPLY=( $( compgen -W "$envs" -- $cur ) ) } complete -F _ghc -o default ghc |

From my experience the first completion is a bit slow but once the flags are cached things work fast.

- Please ignore 7.8.1 release. It shipped with a bug that caused rejection of some valid programs.

`tasty-hunit-adapter`

allows to import existing HUnit tests into tasty (hackage, github):module Main where import Test.HUnit ( (~:), (@=?) ) import Test.Tasty ( defaultMain, testGroup ) import Test.Tasty.HUnit.Adapter ( hUnitTestToTestTree ) main :: IO () main = defaultMain $ testGroup "Migrated from HUnit" $ hUnitTestToTestTree ("HUnit test" ~: 2 + 2 @=? 4)

`tasty-program`

allows to run external program and test whether it terminates successfully (hackage, github):module Main ( main ) where import Test.Tasty import Test.Tasty.Program main :: IO () main = defaultMain $ testGroup "Compilation with GHC" $ [ testProgram "Foo" "ghc" ["-fforce-recomp", "foo.hs"] Nothing ]

This package has only this basic functionality at the moment. A missing feature is the possibility of logging stdout and stderr to a file so that it can later be inspected or perhaps used by a golden test (but for the latter tasty needs test dependencies).

As a response to the test-framework package being unmaintained Roman Cheplyaka has released tasty (original announcement here). Since its release in August 2013 tasty has received packages supporting integration with QuickCheck, HUnit, SmallCheck, hspec as well as support for golden testing and few others. I decided to give tasty a try and use it in my haskell-testing-stub project. Tasty turned out to be almost a drop-in replacement for test-framework. I had to update cabal file (quite obviously), change imports to point to tasty rather than test-framework and replace usage of `[Test]`

type with `TestTree`

. The only problem I encountered was adapting tests from HUnit. It turns out that tasty-hunit package does not have a function that allows to use an existing suite of HUnit tests. That feature was present in test-framework-hunit as `hUnitTestToTests`

function. I mailed Roman about this and his reply was that this was intentional as he does not “believe it adds anything useful to the API (i.e. the way to *write* code).” That’s not a big issue though as it was easy to adapt the missing function (although I think I’ll just put it in a separate package and release it so others don’t have to reinvent the wheel).

I admit that at this point I am not sure whether switching from test-framework to tasty is a good move. The fact that tasty is actively developed is a huge plus although test-framework has reached a mature state so perhaps active development is no longer of key importance. Also, test-framework still has more supporting libraries than tasty. Migrating them should be easy but up till now no one has done it. So I’m not arguing heavily for tasty. This is more like an experiment to see how it works.

]]>- Fun with type functions (2011) – Simon PJ’s presentation of the tutorial paper with the same title. Covers associated data types and type families (see “Associated Types With Class” for an in-depth presentation) + some stuff found in Data Parallel Haskell (read “Data Parallel Haskell: a status report” for more details). The whole presentation feels like a teaser as it ends quite quickly and skips some really interesting examples found in the paper.
- Types a la Milner (2012) by Benjamin C. Pierce (he’s the author of the book about types “Types and Programming Languages”). The talk covers a bit of programming languages history, type systems in general (“well-typed programs don’t go wrong”), type inference in the presence of polymorphism and using types to manage security of personal information. I found the type inference and historical parts very interesting.
- The trouble with types (2013) by Martin Odersky (creator of Scala). Talk covers the role of types in programming, presents the spectrum of static type systems and then focuses on innovations in the type system of Scala.
- I also found an interesting blog hosted on GitHub. Despite only 10 posts the blog has lot’s of stuff on practical type level programming in Haskell. Highly recommended.

Draft version of the paper can be downloaded here. It comes with companion source code that contains a thorough discussion of concepts presented in the paper as well as others that didn’t make it into publication due to space limitations. Companion code is available at GitHub (tag “blog-post-draft-release” points to today’s version). The paper is mostly finished. It should only receive small corrections and spelling fixes. However, if you have any suggestions or comments please share them with me – submission deadline is in three weeks so there is still time to include them.

]]>First and foremost I am using Linux on all of my machines. Debian is my distro of choice, but any *nix based system will do. That said I believe things I describe below can’t be done on Windows. Unless you’re using Cygwin. But then again if you work under Cygwin then maybe it’s time to switch to Linux instead of faking it?

One thing I quickly learned is that it is useful to have access to different versions of GHC and – if you’re working on the backend – LLVM. It is also useful to be able to install latest GHC HEAD as your system-wide GHC installation. I know there are tools designed to automate sandboxing, like hsenv, but I decided to use sandboxing method described by Edsko. This method is essentially based on setting your path to point to certain symlinks and then switching these symlinks to point to different GHC installations. Since I’ve been using this heavily I wrote a script that manages sandboxes in a neat way. When run without parameters it displays list of sandboxes in a fashion identical to `git branch`

command. When given a sandbox name it makes that sandbox active. It can also add new and remove existing sandboxes. It is even smart enough to prevent removal of a default sandbox. Finally, I’ve set up my `.bashrc`

file to provide auto-completion of sandbox names. Here’s how it looks in practice (click to enlarge):

This is probably obvious to anyone working under Linux: script as much as you can. If you find yourself doing something for the second or third time then this particular activity should be scripted. I know how hard it is to convince yourself to dedicate 10 or 15 minutes to write a script when you can do the task in 1 minute, but this effort will quickly pay off. I have scripts for pulling the GHC source repositories (even though I do it really seldom), resetting the GHC build tree, starting tmux sessions and a couple of other things.

In the beginning I wrote my scripts in an ad-hoc way with all the paths hardcoded. This turned out to be a pain when I decided to reorganize my directory structure. The moral is: define paths to commonly used directories as environment variables in your shell’s configuration file (`~/.bashrc`

in case of bash). Once you’ve done that make your scripts dependent on that variables. This will save you a lot of work when you decide to move your directories around. I’ve also defined some assertion functions in my `.bashrc`

file. I use them to check whether the required variables are set and if not the script fails gracefully.

Bash has a built-in auto-completion support. It allows you to get auto-completion of parameters for the commonly used commands. I have auto-completion for cabal and my sandbox management scripts. When GHC 7.8 comes out it will have support for auto-completion as well.

I use Emacs for development despite my initial scepticism. Since configuring Emacs is a nightmare I started a page on GHC wiki to gather useful tips, tricks and configurations in one place so that others can benefit from them. Whatever editor you are using make sure that you take as much advantage of its features as possible.

GHC wiki describes how to set up Firefox to quickly find tickets by number. Use that to your benefit.

Geoffrey Mainland managed to convince me to use `make`

and I thank him for that. Makefiles are a great help if you’re debugging GHC and need to repeatedly recompile a test case and possibly analyse some Core or Cmm dumps. Writing the first Makefile is probably the biggest pain but later you can reuse it as a template. See here for some example Makefiles I used for debugging.

The goal of this post was to convince you that spending time on configuring and scripting your GHC development environment is an investment. It will return and it will allow you to focus on important things that really require your attention. Remember that most of my configuration and scripts described in this post is available on github.

]]>A type system can be regarded as calculating a kind of static approximation to the run-time behaviours of the terms in a program.

So if a type system is a static approximation of program’s behaviour at runtime a natural question to ask is: “how accurate this approximation can be?” Turns out it can be very accurate.

Let’s assume that we have following definition of natural numbers^{1}:

data Nat : Set where zero : Nat suc : Nat → Nat |

First constructor – `zero`

– says that zero is a natural number. Second – `suc`

– says that successor of any natural number is also a natural number. This representation allows to encode `0`

as `zero`

, `1`

as `suc zero`

, `2`

as `suc (suc zero)`

and so on^{2}. Let’s also define a type of booleans to represent logical true and false:

data Bool : Set where false : Bool true : Bool |

We can now define a `≥`

operator that returns `true`

if its arguments are in greater-equal relation and `false`

if they are not:

_≥_ : Nat → Nat → Bool m ≥ zero = true zero ≥ suc n = false suc m ≥ suc n = m ≥ n |

This definition has three cases. First says that any natural number is greater than or equal to zero. Second says that zero is not greater than any successor. Final case says that two non-zero natural numbers are in ≥ relation if their predecessors are also in that relation. What if we replace `false`

with `true`

in our definition?

_≥_ : Nat → Nat → Bool m ≥ zero = true zero ≥ suc n = true suc m ≥ suc n = m ≥ n |

Well… nothing. We get a function that has nonsense semantics but other than that it is well-typed. The type system won’t catch this mistake. The reason for this is that our function returns a result but it doesn’t say why that result is true. And since `≥`

doesn’t give us any evidence that result is correct there is no way of statically checking whether the implementation is correct or not.

But it turns out that we can do better using dependent types. We can write a comparison function that proves its result correct. Let’s forget our definition of `≥`

and instead define datatype called `≥`

:

data _≥_ : Nat → Nat → Set where ge0 : { y : Nat} → y ≥ zero geS : {x y : Nat} → x ≥ y → suc x ≥ suc y |

This type has two `Nat`

indices that parametrize it. For example: `5 ≥ 3`

and `2 ≥ 0`

are two distinct types. Notice that each constructor can only be used to construct values of a specific type: `ge0`

constructs a value that belongs to types like `0 ≥ 0`

, `1 ≥ 0`

, `3 ≥ 0`

and so on. `geS`

given a value of type `x ≥ y`

constructs a value of type `suc x ≥ suc y`

.

There are a few interesting properties of `≥`

datatype. Notice that not only `ge0`

can construct value of types `y ≥ 0`

, but it is also the only possible value of such types. In other words the only value of `0 ≥ 0`

, `1 ≥ 0`

or `3 ≥ 0`

is `ge0`

. Types like `5 ≥ 3`

also have only one value (in case of `5 ≥ 3`

it is `geS (geS (geS ge0))`

). That’s why we call `≥`

a *singleton type*. Note also that there is no way to construct values of type `0 ≥ 3`

or `5 ≥ 2`

– there are no constructors that we could use to get a value of that type. We will thus say that `≥`

datatype is a witness (or evidence): if we can construct a value for a given two indices then this value is a witness that relation represented by the `≥`

datatype holds. For example `geS (geS ge0))`

is a witness that relations `2 ≥ 2`

and `2 ≥ 5`

hold but there is no way to provide evidence that `0 ≥ 1`

holds. Notice that previous definition of `≥`

function had three cases: one base case for `true`

, one base case for `false`

and one inductive case. The `≥`

datatype has only two cases: one being equivalent of `true`

and one inductive. Because the value of `≥`

exists if and only if its two parameters are in ≥ relation there is no need to represent `false`

explicitly.

We have a way to express proof that one value is greater than another. Let’s now construct a datatype that can say whether one value is greater than another and supply us with a proof of that fact:

data Order : Nat → Nat → Set where ge : {x : Nat} {y : Nat} → x ≥ y → Order x y le : {x : Nat} {y : Nat} → y ≥ x → Order x y |

Order is indexed by two natural numbers. These numbers can be anything – there is no restriction on any of the constructors. We can construct values of Order using one of two constructors: `ge`

and `le`

. Constructing value of `Order`

using `ge`

constructor requires a value of type `x ≥ y`

. In other words it requires a proof that `x`

is greater than or equal to `y`

. Constructing value of `Order`

using `le`

constructor requires the opposite proof – that `y ≥ x`

. `Order`

datatype is equivalent of `Bool`

except that it is specialized to one particular relation instead of being a general statement of truth or false. It also carries a proof of the fact that it states.

Now we can write a function that compares two natural numbers and returns a result that says whether first number is greater than or equal to the second one^{3}:

order : (x : Nat) → (y : Nat) → Order x y order x zero = ge ge0 order zero (suc b) = le ge0 order (suc a) (suc b) with order a b order (suc a) (suc b) | ge a≥b = ge (geS a≥b) order (suc a) (suc b) | le b≥a = le (geS b≥a) |

In this implementation `ge`

plays the role of `true`

and `le`

plays the role of `false`

. But if we try to replace `le`

with `ge`

the way we previously replaced `false`

with `true`

the result will not be well-typed:

order : (x : Nat) → (y : Nat) → Order x y order x zero = ge ge0 order zero (suc b) = ge ge0 -- TYPE ERROR order (suc a) (suc b) with order a b order (suc a) (suc b) | ge a≥b = ge (geS a≥b) order (suc a) (suc b) | le b≥a = le (geS b≥a) |

Why? It is a direct result of the definitions that we used. In the second equation of `order`

, `x`

is `zero`

and `y`

is `suc b`

. To construct a value of `Order x y`

using `ge`

constructor we must provide a proof that `x ≥ y`

. In this case we would have to prove that `zero ≥ suc b`

, but as discussed previously there is no constructor of `≥`

that could construct value of this type. Thus the whole expression is ill-typed and the incorrectness of our definition is caught at compile time.

The idea that types can represent logical propositions and values can be viewed as proofs of these propositions is not new – it is known as Curry-Howard correspondence (or isomorphism) and I bet many of you have heard that name. Example presented here is taken from “Why Dependent Types Matter”. See this recent post for a few more words about this paper.

- All code in this post is in Agda.
- For the sake of readability I will write Nats as numerals, not as applications of suc and zero. So remember that whenever I write 2 I mean
`suc (suc zero)`

- Note that in Agda
`a≥b`

is a valid identifier, not an application of`≥`

- Standard library in Idris feels friendlier than in Agda. It is bundled with the compiler and doesn’t require additional installation (unlike Agda’s). Prelude is by default imported into every module so programmer can use Nat, Bool, lists and so on out of the box. There are also some similarities with Haskell prelude. All in all, standard library in Idris is much less daunting than in Agda.
- Idris is really a programming language, i.e. one can write programs that actually run. Agda feels more like a proof assistant. According to one of the tutorials I’ve read you can run programs written in Agda, but it is not as straightforward as in Idris. I personally I haven’t run a single Agda program – I’m perfectly happy that they typecheck.
- Compared to Agda Idris has limited Unicode support. I’ve never felt the need to use Unicode in my source code until I started programming in Agda – after just a few weeks it feels like an essential thing. I think Idris allows Unicode only in identifiers, but doesn’t allow it in operators, which means I have to use awkward operators like
`<!=`

instead of ≤. I recall seeing some discussions about Unicode at #idris channel, so I wouldn’t be surprised if that changed soon. - One of the biggest differences between Agda and Idris is approach to proofs. In Agda a proof is part of function’s code. Programmer is assisted by agda-mode (in Emacs) which guides code writing according to types (a common feature in dependently typed languages). Over the past few weeks I’ve come to appreciate convenience offered by agda-mode: automatic generation of case analysis, refinement of holes, autocompletion of code based on types to name a few. Idris-mode for Emacs doesn’t support interactive development. One has to use interactive proof mode provided in Idris REPL – this means switching between terminal windows, which might be a bit inconvenient. Proofs in Idris can be separated from code they are proving. This allows to write code that is much clearer. In proof mode one can use tactics, which are methods used to convert proof terms in order to reach a certain goal. Generated proof can then be added to source file. It is hard for me to decide which method I prefer. The final result is more readable in Idris, but using tactics is not always straightforward. I also like interactive development offered by Agda. Tough choice.
- Both languages are poorly documented. That said, Idris has much less documentation (mostly papers and presentations by Edwin Brady). I expect this to change, as the Idris community seems to be growing (slowly, but still).
- One thing I didn’t like in Idris are visibility qualifiers used to define how functions and datatypes are exported from the module. There are three available: public (export name and implementation), private (don’t export anything) and abstract (export type signature, but don’t export implementation). This is slightly different than in Haskell – I think that difference comes from properties of dependent types. What I didn’t like are rules and syntax used to define export visibility. Visibility for a function or datatype can be defined by annotating it with one of three keywords: public, private, abstract. If all definitions in a module are not annotated then everything is public. But if there is at least one annotation everything without annotation is private. Unless you changed the default visibility, in which case everything without annotation can be abstract! In other words if you see a definition without annotation it means that: a) it can be public, but you have to check if all other definitions are without annotations; b) private, if at least one other definition is annotated – again, you have to check whole file; c) but it can be abstract as well – you need to check the file to see if the default export level was set. The only way to be sure – except for nuking the entire site from orbit – is annotating every function with an export modifier, but that feels very verbose. I prefer Haskell’s syntax for defining what is exported and what is not and I think it could be easily extended to support three possible levels of export visibility.
- Unlike Agda, Idris has case expressions. They have some limitations however. I’m not sure whether these limitations come from properties of dependently typed languages or are they just simplifications in Idris implementation that could theoretically be avoided.
- Idris has lots of other cool features. Idiom brackets are a syntactic sugar for applicative style: you can write
`[| f a b c |]`

instead of`pure f <*> a <*> b <$*gt; c`

. Idris has syntax extensions designed to support development of EDSLs. Moreover tuples are available out of the box, there’s do-notation for monadic expressions, there are list comprehensions and Foreign Function Interface. - One feature that I’m a bit sceptical about are “implicit conversions” that allow to define implicit casts between arguments and write expressions like
`"Number " ++ x`

, where`x`

is an`Int`

. I can imagine this could be a misfeature. - Idris has “using” notation that allows to introduce definitions that are visible throughout a block of code. Most common use seems to be in definition of data types. Agda does it better IMO by introducing type parameters into scope of data constructors.
- Idris seems to be developed more actively. The repos are stored on github so anyone can easily contribute. This is not the case with Agda, which has Darcs repos and the whole process feels closed (in a sense “not opened to community”). On the other hand mailing list for Idris is set up on Google lists, which is a blocker for me.

All in all programming in Idris is also fun although it is slightly different kind of fun than in Agda. I must say that I miss two features from Agda: interactive development in Emacs and Unicode support. Given how actively Idris is developed I imagine it could soon become more popular than Agda. Perhaps these “missing” features will also be added one day?

As an exercise I rewrote code from “Why dependent types matter” paper from Agda (see my previous post) to Idris. Code is available in on github.

]]>Recently I decided to solidify my knowledge of basics of dependent types by reading “Why Dependent Types Matter”. This unpublished paper was written by Thorsten Altenkirch, Conor McBride and James McKinna somewhere in 2006 I believe. It gives a great overview of dependent types and various design decisions related to their usage. But most of all this paper shows how to write a provably correct merge-sort algorithm. Proving correctness of algorithms is something I find very interesting, so this paper was a must-read for me.

There is only one catch with “Why Dependent Types Matter”. All the code is written in Epigram, a dependently typed functional language designed by Conor McBride and James McKinna. The problem is that Epigram’s webpage has been offline for few months now^{1} and the language basically seems dead. Anyway, since my dependently-typed language of choice is Agda (for the moment at least – I’m thinking a lot about Idris recently) I decided to rewrite all the code in the paper to Agda. For the most part this was a straightforward task, once I learned how to read Epigram’s unusual syntax. There were however a few bumps along the way. One problem I encountered early on was Agda’s termination checker complaining about some functions. Luckily, Agda community is as helpful as Haskell’s and within a day I was given a detailed explanation of what goes wrong. A slightly larger problem was that paper elides details of some proofs. If I wanted to have working Agda code I had to fill in these details. Since I didn’t know how to do that I had to pause for one day and go through online materials for Thorsten Altenkirch’s course on Computer Aided Formal Reasoning. In the end I managed to fill in all the missing gaps. My code is available on github. Now I feel ready to prove correctness of a few more algorithms on my own.

Conor will be giving his course on “Dependently typed metaprogramming” in November and December at University of Edinburgh. See here for details. Be sure not to miss it if you have a chance to attend. Code repository for the course is available here.

Unofficial mirror of Epigram’s sources is available on github.

- I recall Conor mentioning that Nottingham people, who were hosting it Epigram’s web page on their servers, sent him the hard drive with said web page.

I already mentioned in my earlier post that Cmm is a low-level language, something between C and assembly. Cmm is produced from another intermediate language, STG. A single Cmm procedure is represented as a directed graph. Each node in a graph is a Cmm Block of low level instructions. Exactly one Cmm Block in a graph is an entry point – a block from which the execution starts when procedure represented by a graph is called. Most Cmm Blocks in a graph have at least one successor, that is node(s) to which control flows from a given Cmm Block. A Cmm Block may not have a successor if it is a call to another procedure, i.e. it passes flow of control to another Cmm graph. Each Cmm Block consists of a linear list of Cmm Nodes. A Cmm Node represents a single Cmm instruction like store to a register, conditional jump or call to a function.

Cmm representation produced by the STG -> Cmm pass is incomplete. For example operations on the stack are represented in an abstract way. It is also far from being optimal as it may contain lots of empty blocks or control flow paths that will never be taken. That’s why we have Cmm pipeline. It takes Cmm representation produced by the code generator^{1} and applies a series of transformations to it. Some of them are mandatory (like stack layout), while others perform optimisations and are completely optional. Here’s a rough overview of the pipeline:

**Control Flow Optimisations.**Optimises structure of a graph by concatenating blocks and omitting empty blocks.**Common Block Elimination (optional).**Eliminates duplicate blocks.**Minimal Proc-point set.**Determines a minimal set of proc-points^{2}.**Stack Layout.**Turns abstract stack representation into explicit stack pointer references. Requires proc-point information computed in step 3. Creates stack maps.**Sinking pass (optional).**Moves variable declarations closer to their usage sites. Inlines some literals and registers in a way similar to constant propagation.**CAF analysis.**Does analysis of constant-applicative forms (top-level declarations that don’t have any parameters). CAF information is returned by the Cmm pipeline together with optimized Cmm graph.**Proc-point analysis and proc-point splitting (optional).**Here the pipeline splits into two alternative flows. They are identical except for the fact that one branch begins by performing proc-point splitting. This means that blocks that were determined to be proc-points are now turned into separate procedures. Requires proc-point information computed in step 3.**Info Tables.**Populates info tables of each Cmm function with stack usage information. Uses stack maps created by the stack layout (step 4).**Control Flow Optimisations (optional).**Repeat control flow optimisations (step 1), but this time this is optional.**Unreachable Blocks Removal.**Eliminates blocks that don’t have a predecessor in the Cmm graph.

As an example consider this Cmm produced by the code generator:

c4wk: goto c4wi; c4wi: goto c4wl; c4wl: goto c4wm; c4wm: if ((old + 0) - <highSp> < SpLim) goto c4x9; else goto c4xa; c4x9: R2 = _s2Rv::P64; R1 = _s2Ru::P64; call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8; |

After going through the Cmm pipeline the empty blocks are eliminated and abstract stack representation (`(old + 0)`

and `<highSp>`

) is turned into explicit stack usage:

c4wi: if (Sp - 88 < SpLim) goto c4x9; else goto c4xa; c4x9: R2 = _s2Rv::P64; R1 = _s2Ru::P64; call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8; |

During my work on the Cmm pipeline I encountered following bugs and design issues:

- In some cases the Stack Layout phase (step 4) can invalidate the minimal set of proc-points by removing a block that was earlier determined to be a proc-point. However, minimal proc-point information is later used by proc-point analysis. GHC would panic if a proc-point block was removed. This was bug #8205. I solved it by adding additional check in the proc-point analysis that ensures that all proc-points actually exist in a graph. This was a simple, one line solution, but it doesn’t feel right. It accepts the fact that our data is in an inconsistent state and places the responsibility of dealing with that on algorithms relying on that state. In other words, any algorithm that relies on minimal proc-point set after the stack layout must check whether given proc-points exist in a graph.
- I observed that in some circumstances control flow optimisation pass may lead to unexpected duplication of blocks (see #8456). After some investigation it turned out that this pass began by computing set of predecessors for each block and then modified the graph based on this information. The problem was that the list of predecessors was not being updated as the graph was modified. This problem is the same as the previous one: we compute a fact about our data structure and based on that fact we start modifying the data but we don’t update the fact as we go.
- Control flow optimisations pass may produce unreachable blocks. They remain in the data structure representing the graph, but they are not reachable from any block in the graph. The common block elimination pass will remove the unreachable blocks but before it does the data is in an inconsistent state.
- Same thing happens later: stack layout pass may create unreachable blocks and relies on later passes to remove them.

I listed only the problems I am aware of but I believe there are more and they will manifest themselves one day. I spent last couple of days thinking how to solve these issues. Of course fixing each of them separately is a relatively simple task, but I’m trying to come up with some general design that would prevent us from introducing inconsistencies in our data structures.

- That’s how we often refer to STG -> Cmm pass
- I want to avoid going into details of what are proc-points and why do we need them. For the purpose of this post it is sufficient that you consider proc-point as a property that might be assigned to a block based on its predecessors