How to make Idris warn of incomplete cases/matches? - idris

For example when implementing a Show instance for the following type:
data Shape = Circle Double
| Box Vector2D
| Polygon (List Vector2D)
| Chain (List Vector2D)
...and omitting the Chain case, Idris will successfully type check this file.
Similar issues go for implementing other functions.
Adding %default total at the beginning of the file doesn't seem to help this, but my impression was that it should.

With this:
%default total
data DataType = A | B | C
Show DataType where
show A = "A"
I get
$ idris Testme.idr
Type checking ./Testme.idr
Testme.idr:5:1-13:
|
5 | Show DataType where
| ~~~~~~~~~~~~~
Main.DataType implementation of Prelude.Show.Show is possibly not total due to: Prelude.Show.Main.DataType implementation of Prelude.Show.Show, method show
Please note that you will not see this kind of warnings in Atom - they do not seem part of the compiler / editor protocol.

There is an option you can call idris with:
--total Require functions to be total by default
I'm still not sure if this is the only way, why %default total seems to do nothing, and whether it's possible to only get a warning when a function is not total.

Related

What does justify the use of coroutines instead of subroutines?

I am currently exploring coroutines in Python, but I have difficulties in determining when to use them over normal subroutines. I am trying to explain my problem with the help of an example.
The task is to iterate over tabular data and format the content of the row according to its entry in the type field. When formatted, the result is written to the same output file.
index | type | time | content
-----------------------------
0 | A | 4 | ...
1 | B | 6 | ...
2 | C | 9 | ...
3 | B | 11 | ...
...
Normally, I would check the type and write some sort of switch case and delegate the data to a specific subroutine (== function) like so (pseudo-code):
outfile = open('test.txt')
for row in infile:
switch(row.type)
{
case A:
format_a(row.content, outfile) // subroutine that formats and writes data of type A
break
case B:
format_b(row.content, outfile) // same for type B...
break
case C:
format_c(row.content, outfile) // ... and type C
break
default:
// handle unknown type exception
break
}
close(outfile)
The question is: would I get any benefit from realizing this with coroutines? I don't think so, and let me explain why: if I have determined the type of a row, I would pass the content to the respective coroutine. As long as I do this, the other coroutines and the calling function are paused. The data is formatted and written to the file and passes control back to the calling function which gets the next row, etc. This procedure repeats until I run out of rows. Therefore, this is exactly what the workflow using subroutines would look like.
One pro for using coroutines here would be if I had to keep track of some state. Maybe I am interested in the time difference to the last row per type. In this case, the coroutine function for B would save the time of its first call (6). When it is called the second time, it retrieves the value (11) and can calculate the difference (11 - 6 = 5). This would be way harder to do with subroutines.
But is the argument of keeping track of some state the only reason for using coroutines? I am looking for a rule-of-thumb, not a rule that covers every case possible.

Function iMA is returning different return value from expected (MQL5)

I'm using MQL5 (my first code).
I want to use a script that uses MA, but first, I wanted to confirm the value to verify I'm doing correctly. Using a very basic code into script:
double x=0;
x = iMA(Symbol(),Period(),100,0,MODE_SMA,PRICE_CLOSE);
Alert("The actual MA from last 100 points of EURUSD actually is: " + x;
The expected value is near the actual price... 1.23456, but this function is returning 10.00000 or 11.0000.
I believe I'm missing something, and https://www.mql5.com/es/docs/indicators/ima helplink is not quite clear enough.
I already saw another similar function: MA[0] which seems to bring the moving average from specific candle, but, I don't know how to manage the Period range (100) or if is related to Close/Open variables on it. I didn't find any specific helplink to review.
Any ideas are very appreciated!!!
x should be int, it is a handler of the MA. So each indicator when created in MT5 receives its handler, and you can use it later to get what you need. If you need several MA's - create several handlers and give each of them different names (x1, x2 or add some sense). Expert advisors in the default build of MT5 are good examples on what to do.
The iMA function Returns the handle of a specified technical indicator, not the "moving average" value.
For example, to get the value of the Moving average you can use this (in MQ4):
EMA34Handler = iMA(NULL,0,34,0,MODE_EMA,PRICE_CLOSE);
EMA34Value = CopyBuffer(EMA34Handler, 0,0);

menhir - associate AST nodes with token locations in source file

I am using Menhir to parse a DSL. My parser builds an AST using an elaborate collection of nested types. During later typecheck and other passes in error reports generated for a user, I would like to refer to source file position where it occurred. These are not parsing errors, and they generated after parsing is completed.
A naive solution would be to equip all AST types with additional location information, but that would make working with them (e.g. constructing or matching) unnecessary clumsy. What are the established practices to do that?
I don't know if it's a best practice, but I like the approach taken in the abstract syntax tree of the Frama-C system; see https://github.com/Frama-C/Frama-C-snapshot/blob/master/src/kernel_services/ast_data/cil_types.mli
This approach uses "layers" of records and algebraic types nested in each other. The records hold meta-information like source locations, as well as the algebraic "node" you can match on.
For example, here is a part of the representation of expressions:
type ...
and exp = {
eid: int; (** unique identifier *)
enode: exp_node; (** the expression itself *)
eloc: location; (** location of the expression. *)
}
and exp_node =
| Const of constant (** Constant *)
| Lval of lval (** Lvalue *)
| UnOp of unop * exp * typ
| BinOp of binop * exp * exp * typ
...
So given a variable e of type exp, you can access its source location with e.eloc, and pattern match on its abstract syntax tree in e.enode.
So simple, "top-level" matches on syntax are very easy:
let rec is_const_expr e =
match e.enode with
| Const _ -> true
| Lval _ -> false
| UnOp (_op, e', _typ) -> is_const_expr e'
| BinOp (_op, l, r, _typ) -> is_const_expr l && is_const_expr r
To match deeper in an expression, you have to go through a record at each level. This adds some syntactic clutter, but not too much, as you can pattern match on only the one record field that interests you:
let optimize_double_negation e =
match e.enode with
| UnOp (Neg, { enode = UnOp (Neg, e', _) }, _) -> e'
| _ -> e
For comparison, on a pure AST without metadata, this would be something like:
let optimize_double_negation e =
match e.enode with
| UnOp (Neg, UnOp (Neg, e', _), _) -> e'
| _ -> e
I find that Frama-C's approach works well in practice.
You need somehow to attach the location information to your nodes. The usual solution is to encode your AST node as a record, e.g.,
type node =
| Typedef of typdef
| Typeexp of typeexp
| Literal of string
| Constant of int
| ...
type annotated_node = { node : node; loc : loc}
Since you're using records, you can still pattern match without too much syntactic overhead, e.g.,
match node with
| {node=Typedef t} -> pp_typedef t
| ...
Depending on your representation, you may choose between wrapping each branch of your type individually, wrapping the whole type, or recursively, like in Frama-C example by #Isabelle Newbie.
A similar but more general approach is to extend a node not with the location, but just with a unique identifier and to use a final map to add arbitrary data to nodes. The benefit of this approach is that you can extend your nodes with arbitrary data as you actually externalize node attributes. The drawback is that you can't actually guarantee the totality of an attribute since finite maps are no total. Thus it is harder to preserve an invariant that, for example, all nodes have a location.
Since every heap allocated object already has an implicit unique identifier, the address, it is possible to attach data to the heap allocated objects without actually wrapping it in another type. For example, we can still use type node as it is and use finite maps to attach arbitrary pieces of information to them, as long as each node is a heap object, i.e., the node definition doesn't contain constant constructors (in case if it has, you can work around it by adding a bogus unit value, e.g., | End can be represented as | End of unit.
Of course, by saying an address, I do not literally mean the physical or virtual address of an object. OCaml uses a moving GC so an actual address of an OCaml object may change during a program execution. Moreover, an address, in general, is not unique, as once an object is deallocated its address can be grabbed by a completely different entity.
Fortunately, after ephemera were added to the recent version of OCaml it is no longer a problem. Moreover, an ephemeron will play nicely with the GC, so that if a node is no longer reachable its attributes (like file locations) will be collected by the GC. So, let's ground this with a concrete example. Suppose we have two nodes c1 and c2:
let c1 = Literal "hello"
let c2 = Constant 42
Now we can create a location mapping from nodes to locations (we will represent the latter as just strings)
module Locations = Ephemeron.K1.Make(struct
type t = node
let hash = Hashtbl.hash (* or your own hash if you have one *)
let equal = (=) (* or a specilized equal operator *)
end)
The Locations module provides an interface of a typical imperative hash table. So let's use it. In the parser, whenever you create a new node you should register its locations in the global locations value, e.g.,
let locations = Locations.create 1337
(* somewhere in the semantics actions, where c1 and c2 are created *)
Locations.add c1 "hello.ml:12:32"
Locations.add c2 "hello.ml:13:56"
And later, you can extract the location:
# Locations.find locs c1;;
- : string = "hello.ml:12:32"
As you see, although the solution is nice in the sense, that it doesn't touch the node data type, so the rest of your code can pattern match on it nice and easy, it is still a little bit dirty, as it requires global mutable state, that is hard to maintain. Also, since we are using an object address as a key, every newly created object, even if it was logically derived from the original object, will have a different identity. For example, suppose you have a function, that normalizes all literals:
let normalize = function
| Literal str -> Literal (normalize_literal str)
| node -> node
It will create a new Literal node from the original nodes, so all the location information will be lost. That means, that you need to update the location information, every time you derive one node from another.
Another issue with ephemera is that they can't survive the marshaling or serialization. I.e., if you store your AST somewhere in a file, and then you restore it, all nodes will loose their identity, and the location table will become empty.
Speaking of the "monadic approach" that you mentioned in comments. Though monads are magic, they still can't magically solve all the problems. They are not silver bullets :) In order to attach something to a node we still need to extend it with an extra attribute - either a location information directly or an identity through which we can attach properties indirectly. The monad can be useful for the latter though, as instead of having a global reference to the last assigned identifier, we can use a state monad, to encapsulate our id generator. And for the sake of completeness, instead of using a state monad or a global reference to generate unique identifiers, you can use UUID and get identifiers that are not only unique in a program run, but are also universally unique, in the sense that there are no other objects in the world with the same identifier, no matter how often you run your program (in the sane world). And although it looks like that generating the UUID doesn't use any state, underneath the hood it still uses an imperative random number generator, so it is sort of cheating, but still can seen as pure functional, as it doesn't contain observable effects.

Can't create simple binary data structure with IdrisNet2

I am trying to use the IdrisNet2 library to define some binary data structures. I am using Idris 0.9.17.1 and commit 262b746c9a2405e43d1de6a48de44cac2fd19932 of IdrisNet2. I am defining a packet with one 16 bit field:
module Main
import IdrisNet.PacketLang
import Data.So
myPacket : PacketLang
myPacket = with PacketLang do
bits 16
main : IO ()
main = putStrLn "hello"
I get the compiler error:
Can't solve goal
So (fromInteger 16 > fromInteger 0)
What exactly is the problem and how can I fix it? I am guessing that I need to prove to the compiler that 16 is greater than 0, but I'm not sure how to do this in Idris or why this is necessary.
Sorry about that. A while back we decided to standardize on uppercase for all the types and their constructors; that meant oh and so got renamed to Oh and So. So there was an update to this lib to get it to compile, but it looks like an oh in the default tactics to solve an implicit param got overlooked:
https://github.com/SimonJF/IdrisNet2/blob/master/src/IdrisNet/PacketLang.idr#L149
So that tactic would always fail (oh is an undefined reference). You could explicitly pass the value of p there, and that would work: bits 16 {p = Oh}.
But I've submitted a pull request to fix that issue in the lib: https://github.com/SimonJF/IdrisNet2/pull/11

Parameter 3 is not constant in call of system task $fwrite

I am using Xilinx ISE 10.1 to run some verilog code. In the code I want to write the register values of 3 registers in a file, cipher.txt. The following is the code snippet:
if (clk_count==528) begin
f1 = $fopen("cipher.txt", "w");
$fwrite(f1, "clk: %d", clk_count[11:0]);
$fwrite(f1, "plain: %h", plain[31:0]);
$fwrite(f1, "cipher: %h", cipher[31:0]);
$fclose(f1);
end
At the end of execution, the contents of cipher.txt is found as:
clk: %dplain: %hcipher: %h
There is no other error encountered, but a warning comes up corresponding to the 3 fwrite's:
Parameter 3 is not constant in call of system task $fwrite.
Parameter 3 is not constant in call of system task $fwrite.
Parameter 3 is not constant in call of system task $fwrite.
The values of the registers clk_count and cipher change on every clock cycle (value of register plain remains constant throughout), and the values are written to cipher.txt when clk_count equals 528 (indicated by the if statement)
Can anybody provide some insight and/or help me get past this hurdle?
Thanks.
It appears that ISE expects the arguments to $fwrite to be constant. The warnings are referring to clk_count[11:0], plain[31:0], and cipher[31:0], which are not constant. By definition they are changing each cycle so they are not known at compile time. This also explains why they are not printing and you are seeing %d and %h in the output.
There is nothing to my knowledge in the Verilog spec that requires the arguments to $fwrite be constant. The same code works as expected with Cadence Incisive. My guess is that it's a limitation of ISE, so you may want to check with Xilinx.
Possible work-arounds:
1) Use $swrite to create a string with the proper formatting. Then write the string to the file.
2) Try using an intermediate variable in the calls to $fwrite. Maybe the part-selects are throwing it off. e.g.
integer foo;
foo = clk_count[11:0];
$fwrite(... , foo , ...);
Either of those might work, or not.
Out of curiosity, if you remove the part-selects, and try to print clk_count without the [11:0] , do you get the same warnings?