Learn You an Agda
31–40 of 72 posts
Re: Learn You an Agda
#32I like to show you the immense beauty of the Agda standard library: http://agda.github.io/agda-stdlib/html/README.html (all clickable and…you'd better have proper unicode fonts).
Even something as mundane as Data.Bool is beautiful, defining False in terms of bottom. I love to look at unicode, but is it a pain to type it in practice, even given emacs?
[0] http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Docs.Unicod...
Re: Learn You an Agda
#33If we can construct a value of a certain type, we have simultaneously constructed a proof that the theorem encoded by that type holds. data _even : ℕ → Set where I do not understand how to interpret this passage. _ even, given a number, returns a type? in this case, zero even is a type, but we have not created any value with that type. What am I missing?
Re: Learn You an Agda
#34Languages that use types for elaborate proofs always seem to me like they only prove the most uninteresting properties of programs, namely the parts that deal with data transformations. Not that data transformations aren't important, but the properties they need to preserve are usually easy to be convinced of without any assistance by the compiler. At the end of the day, programs are written for their side effects (u…
> At the end of the day, programs are written for their side effects
The reason for such a focus on data transformation is that it's very easy to do in these purely functional languages (Agda included). It's so easy, in fact, that "other" things, like side effects, event handling, etc. are represented as data transformations. This is most obvious in Haskell, since laziness decouples definition from computation; eg. making it trivial to represent event streams as infinite lists.
> What I'm most interested in is proofs that, say, in a concurrent environment, a function that closes a socket will never be called as long as there are pending tasks to write to the socket.
The usual approach is to define a datatype of operations you might want to perform (eg. `Write String`, `Read Length`, etc.). Next you define a datatype which can combine these operations together in ways you may want (eg. something like a rose tree, if you want threads firing off threads). This forms an "embedded domain-specific language". We then write a bunch of helper functions for manipulating these datastructures (eg. a "combinator library"), then we use these to write down what we actually want as a combination of operations.
Next we write an interpreter function which opens a socket, performs all of the operations in the tree (possibly in multiple threads), waits for them to finish then closes the socket.
> Or, because I write concurrent data structures, I'm interested to prove that a certain function will eventually release all locks it acquires. Are there any such languages?
You can do the same thing as with the socket example, except you can strengthen the type of your program (operation-combining) datastructure to enforce that locks are released. As a simplified example, we can force a serial computation to release locks by only allowing AQUIRE and RELEASE to be inserted together:
data Op = Foo | Bar | Aquire ID | Release ID
data SafeOp = SFoo | SBar
data Program : Type where
NoOp : Program -- Empty Program
WithLock : Program -> Program -- Add lock ops to a Program
PrefixOp : SafeOp -> Program -> Program -- Add a non-lock Op to a Program
Interleave : Program -> Program -> Program -- Combine two Programs
-- Part of the interpreter, not exposed to the world
progToOps : Program -> [Op]
progToOps NoOp = []
progToOps (WithLock id p) = [Aquire id] ++ progToOps p ++ [Release id]
progToOps (PrefixOp SFoo p) = [Foo] ++ progToOps p
progToOps (PrefixOp SBar p) = [Bar] ++ progToOps p
progToOps (Interleave p1 p2) = interleave (progToOps p1) (progToOps p2)
interleave [] ys = ys
interleave (x:xs) ys = [x] ++ interleave ys xs
Notice that progToOps can never output a list containing Aquire without also containing a Release with the same ID. Also notice that we can define arbitrary combinations of the other ops: [] is NoOp
[Foo, Bar] is PrefixOp SFoo (PrefixOp SBar NoOp)
[Foo, Aquire A, Bar, Aquire B, Release A, Foo, Release B] is Interleave (PrefixOp SFoo (PrefixOp SBar NoOp)) (Interleave (WithLock A NoOp) (WithLock B (PrefixOp SFoo NoOp)))
Of course these datastructures would be build up by helper functions instead of by hand, would be tree-like for concurrency, would probably provide guarantees per sub-tree, would allow arbitrary functions (of some suitable type) in place of Foo, Bar, etc.Re: Learn You an Agda
#35If we can construct a value of a certain type, we have simultaneously constructed a proof that the theorem encoded by that type holds. data _even : ℕ → Set where I do not understand how to interpret this passage. _ even, given a number, returns a type? in this case, zero even is a type, but we have not created any value with that type. What am I missing?
In a Dependently Typed (DT) language like Agda the language of values and the language of types are one and the same. Thus, a function from types to types is exactly the same sort of thing as a function from values to values. In this case we have a third sort of totally-natural-day-old-kind-of-thing: a function from values of ℕ to types (in Set). It's "just" a function from values to types.
Now, we annotate values with their types. Thus we might have a new top-level definition
something : zero even
something = _
where we've used our postfix `even` function to construct a type from the value `zero`. Is this type inhabited? That's a question of proof and programming. Regardless of its inhabitation, though, we can clearly see that the notion of `zero even` simply being a type is sound---that's the nature of function application when the target domain is that of Set!Re: Learn You an Agda
#36I like to show you the immense beauty of the Agda standard library: http://agda.github.io/agda-stdlib/html/README.html (all clickable and…you'd better have proper unicode fonts).
Even something as mundane as Data.Bool is beautiful, defining False in terms of bottom. I love to look at unicode, but is it a pain to type it in practice, even given emacs?
What happens in Data.Bool is that we have the function from values to types `T` such that `T true` and `T false` are types equal to top and bottom respectively. This value-to-type encoding is called a "universe" and allows us to talk about propositions which are based on boolean function results like
theorem1 : T (1 - 1 == 0)
which is somewhat interestingly different from theorem2 : 1 - 1 = 0
in that the first will reflect upon the definitions of the (recursive) functions (-) and (==) while the second reflects only upon the definition of (-).Re: Learn You an Agda
#37Languages that use types for elaborate proofs always seem to me like they only prove the most uninteresting properties of programs, namely the parts that deal with data transformations. Not that data transformations aren't important, but the properties they need to preserve are usually easy to be convinced of without any assistance by the compiler. At the end of the day, programs are written for their side effects (u…
It's not exactly what you're asking for but Ur/Web puts an expressive type system to some slightly unusual ends: http://www.impredicative.com/ur/ .
fun list () =
rows
{[fs.T.Id]}
{@mapX2 [fst] [colMeta] [tr]
(fn [nm :: Name] [t ::_] [rest ::_] [[nm] ~ rest] v col =>
{col.Show v}
)
M.fl (fs.T -- #Id) M.cols}
[Update]
[Delete]
);Re: Learn You an Agda
#38I posted this on lobste.rs and somebody stole my link.... Hackernews always gets so much more comments.
Re: Learn You an Agda
#39If I wrote a natural number calculator in Agda; would all my numbers be represented as lists of successions from zero or can the compiler convert them to two's-complement integers as we know and love them? In case the compiler can do that conversion: is it is programmed to do that for some subset of numeric types or can it infer an optimal binary representation of a value somehow? On the other hand, if they really we…
I don't think so, but Natural numbers can't be represented as two's-complement "integers"; neither can Integers.
There are many ways to encode such numbers if you really want; the easiest are probably "Fin (2^32)" for a type with 2^32 members (easy to convert to/from unary Naturals), or "Vect 32 Bool" for a list of 32 Booleans (easy to do bitwise stuff). You'd need to decide how to truncate the Naturals though; do you take min(x, 2^32 - 1)? Do you take x % 2 ^ 32?
Also, note that "S (S (S (S Z)))" isn't really a list; to turn it into a list we'd have to associate some trivial data with each constructor, eg. [NULL, NULL, NULL, NULL].
Re: Learn You an Agda
#40Languages that use types for elaborate proofs always seem to me like they only prove the most uninteresting properties of programs, namely the parts that deal with data transformations. Not that data transformations aren't important, but the properties they need to preserve are usually easy to be convinced of without any assistance by the compiler. At the end of the day, programs are written for their side effects (u…
> Languages that use types for elaborate proofs always seem to me like they only prove the most uninteresting properties of programs, namely the parts that deal with data transformations. > At the end of the day, programs are written for their side effects The reason for such a focus on data transformation is that it's very easy to do in these purely functional languages (Agda included). It's so easy, in fact, that "…