I want to have a subroutine that converts a contents of a numeric
string to a numeric type (int, real, double precision, real(real128)).
However I am getting an error when trying to use Class(*). The error
is shown below:
gfortran -o build/lib/larsa.o -c -ffree-form -g -J./build/lib lib/larsa.f
lib/larsa.f:1933.35:
Read (s, frmt, iostat=ios) num
1
Error: Data transfer element at (1) cannot be polymorphic unless
it is processed by a defined input/output procedure
lib/larsa.f:1935.32:
Read (s, *, iostat=ios) num
1
Error: Data transfer element at (1) cannot be polymorphic unless
it is processed by a defined input/output procedure
This is the subroutine I have written.
Subroutine converts_str_to_num &
( &
s, num, &
fmt, wrn &
)
Character (len=*), Intent (in) :: s
Character (len=*), Intent (in), Optional :: fmt
Class (*) :: num
Character (len=*), Intent (inout), Optional :: wrn
Integer :: ios
Character (len=65) :: frmt
!!$ Reads contents of s and puts value in i.
If (Present (fmt)) Then
frmt = "(" // Trim (fmt) // ")"
Read (s, frmt, iostat=ios) num
Else
Read (s, *, iostat=ios) num
End If
End Subroutine converts_str_to_num
To tidy up the comments, I'll provide an answer.
The error message is clear: you cannot have a polymorphic variable in an input/output list unless the list is processed by defined input/output. This is 9.6.3.5 in Fortran 2008. class(*) num is (unlimited) polymorphic.
Now, for polymorphic derived types you could define such a defined input/output procedure, but that counts as a lot of work and gfortran certainly doesn't (yet) support that notion. Also, you can't do this for intrinsic types. These factors mean you have to deal with non-polymorphic variables in the input list you have.
Of course, it's possible to use generics to avoid polymorphism, but the alternative (as it is for about everything polymorphic) is to use a select type construct. For simplicity, ignore the list-directed and explicit format cases:
select type (assoc => num)
type is (int)
Read (s, *, iostat=ios) assoc
type is (real)
...
type is (...)
class default
error stop "Oh noes!"
end select
I've used an associate name in the select type to address one part of your confusion. If you've just done
select type(num)
type is (int)
Read (s, *, iostat=ios) num
end select
to think that "now using num is fine: why?" that's because the num inside the construct is not the same as the num outside. Crucially, it isn't polymorphic but is the exact type matching the type is.
Related
The following simple code converts an Integer value to a string value and logs it.
module Main where
import Effect (Effect)
import Effect.Console (log)
import Prelude ((<>), Unit, discard)
import Data.Int (toStringAs, radix)
type CustomerFeedback = {
customerServiceScore :: Int,
productQualityScore :: Int,
onTimeDeliveryScore :: Int
}
feedback :: CustomerFeedback
feedback = {
customerServiceScore : 4,
productQualityScore : 2,
onTimeDeliveryScore : 6
}
stringifyCustomerFeedback :: CustomerFeedback -> String
stringifyCustomerFeedback feedback = "Service: " <> toStringAs (radix 10) feedback.customerServiceScore
main ∷ Effect Unit
main = do
log (stringifyCustomerFeedback(feedback))
However, running this code produces the following error:
Could not match type
Maybe Radix
with type
Radix
while checking that type Maybe Radix
is at least as general as type Radix
while checking that expression radix 10
has type Radix
in value declaration stringifyCustomerFeedback
Questions would be as follows:
How do you change the code above so it outputs a string as expected and not an error?
What's the point of a Maybe Radix type if using it where you would use a Radix causes an error? How do you use a Maybe value?
The idea of the radix function is that you give it a number and it creates a Radix from it. But not every number constitutes a valid Radix. For example, if you give it -5, it shouldn't work. And neither should 0 or 1 for example. For some technical reasons, radices above 32 are also deemed invalid.
So that's why it returns Maybe: it would be Nothing in case the number you gave it wasn't a "valid" radix.
And the use case for that function is when you don't actually know the number ahead of time. Like if you get it from the user. Or from some sort of config file or whatnot. In that case, if you get a Nothing, you would interpret that as "invalid user input" or "corrupted config file" and report an error accordingly. And you won't even get as far as calling toStringAs. This is one of the big selling points of static types: applied properly, they can force you to write a correct, reliable program, without ignoring edge cases.
However, in case you already know that you're interested in decimal radix, just use decimal. It's a Maybe-free constant provided by the library, along with some other frequently used ones, such as binary and octal.
stringifyCustomerFeedback feedback = "Service: " <> toStringAs decimal feedback.customerServiceScore
A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.
I'm verifying a c program that uses arrays to store heterogeneous data - in particular, the program uses arrays to implement cons cells, where the first element of the array is an integer value, and the second element is a pointer to the next cons cell.
For example, the free operation for this list would be:
void listfree(void * x) {
if((x == 0)) {
return;
} else {
void * n = *((void **)x + 1);
listfree(n);
free(x);
return;
}
}
Note: Not shown here, but other code sections will read the values of the array and treat it as an integer.
While I understand that the natural way to express this would be as some kind of struct, the program itself is written using an array, and I can't change this.
How should I specify the structure of the memory in VST?
I've defined an lseg predicate as follows:
Fixpoint lseg (x: val) (s: (list val)) (self_card: lseg_card) : mpred := match self_card with
| lseg_card_0 => !!(x = nullval) && !!(s = []) && emp
| lseg_card_1 _alpha_513 =>
EX v : Z,
EX s1 : (list val),
EX nxt : val,
!!(~ (x = nullval)) &&
!!(s = ([(Vint (Int.repr v))] ++ s1)) &&
(data_at Tsh (tarray tint 2) [(Vint (Int.repr v)); nxt] x) *
(lseg nxt s1 _alpha_513)
end.
However, I run into troubles when trying to evaluate void *n = *(void **)x; presumably because the specification states that the memory contains an array of ints not pointers.
The issue is probably as follows, and can almost be solved as follows.
The C semantics permit casting an integer (of the right size) to a pointer, and vice versa, as long as you don't actually do any pointer operations to an integer value, or vice versa. Very likely your C program obeys those rules. But the type system of Verifiable C tries to enforce that local variables (and array elements, etc.) of integer type will never contain pointer values, and vice versa (except the special integer value 0, which is NULL).
However, Verifiable C does support a (proved-foundationally-sound) workaround to this stricter enforcement:
typedef void * int_or_ptr
#ifdef COMPCERT
__attribute((aligned(_Alignof(void*))))
#endif
;
That is: the int_or_ptr type is void*, but with the attribute "align this as void*". So it's semantically identical to void*, but the redundant attribute is a hint to the VST type system to be less restrictive about C type enforcement.
So, when I say "can almost be solved", I'm asking: Can you modify the C program to use an array of "void* aligned as void*" ?
If so, then you can proceed. Your VST verification should use int_or_ptr_type, which is a definition of type Ctypes.type provided by VST-Floyd, when referring to the C-language type of these array elements, or of local variables that these elements are loaded into.
Unfortunately, int_or_ptr_type is not documented in the reference manual (VC.pdf), which is an omission that should be correct. You can look at progs/int_or_ptr.c and progs/verif_int_or_ptr.v, but these do much more than you want or need: They axiomatize operators that distinguish odd integers from aligned pointers, which is undefined in C11 (but consistent with C11, otherwise the ocaml garbage collector could never work). That is, those axiomatized external functions are consistent with CompCert, gcc, clang; but you won't need any of them, because the only operations you're doing on int_or_pointer are the perfectly-legal "comparison with NULL" and "cast to integer" or "cast to struct foo *".
I screwed up on my previous question and had to delete it. Here's a new one:
I got most of this code from this quite helpful site:
module shape_mod
type shape
integer :: color
logical :: filled
integer :: x
integer :: y
contains
procedure :: initialize
end type shape
type, extends(shape) :: rectangle
integer :: length
integer :: width
end type rectangle
type, extends(rectangle) :: square
end type square
interface
subroutine initialize(sh, color, filled, x, y, length, width)
import shape
class(shape) :: sh
integer :: color
logical :: filled
integer :: x
integer :: y
integer, optional :: length
integer, optional :: width
end subroutine
end interface
end module
subroutine initialize(sh, color, filled, x, y, length, width)
! initialize shape objects
class(shape) :: sh
integer :: color
logical :: filled
integer :: x
integer :: y
integer, optional :: length
integer, optional :: width
! do stuff with shape
end subroutine initialize
program drv
use shape_mod
type(shape) :: sh
call sh%initialize(1, .true., 0, 0, 5, 10)
end program
This fails to compile (as it should, as pointed out by respondents to my previous question) with the error:
gfortran shape2.f90
shape2.f90:38:16:
class(shape) :: sh
1
Error: Derived type ‘shape’ at (1) is being used before it is defined
shape2.f90:46:7: Error: Symbol ‘sh’ at (1) has no IMPLICIT type
shape2.f90:47:7: Error: Symbol ‘sh’ at (1) has no IMPLICIT type
shape2.f90:48:7: Error: Symbol ‘sh’ at (1) has no IMPLICIT type
shape2.f90:49:7: Error: Symbol ‘sh’ at (1) has no IMPLICIT type
So, my question is, what can I do to get subroutine initialize() to know about type shape? The only thing I can think of is to put a use statement in:
subroutine initialize(sh, color, filled, x, y, length, width)
use shape_mod
! initialize shape objects
class(shape) :: sh
integer :: color
logical :: filled
...
end subroutine initialize
But that gives me a new error:
gfortran shape2.f90
shape2.f90:37:8:
use shape_mod
1
Error: ‘initialize’ of module ‘shape_mod’, imported at (1), is also the name of the current program unit
How to write the subroutine is the one thing the link I referenced above does not tell. Is there a way to do this? Or does initialiaze() have to be part of shape_mod for this to work?
In the module you have defined an interface for the external procedure initialize. When you use this module in the subroutine definition you have access to the interface of the subroutine itself.
You cannot do this.
Fortunately, you can avoid having the interface accessible by
use shape_mod, only shape
Now, the above is necessary because of the design made to use an external procedure in the type binding. In general, one would expect not to use an external procedure in this way. As we've seen, there's the additional complexity in using an external procedure, both with having to use the module where the type is defined, but also in having to manually specify the procedure's interface.
There are times where an external interface would be useful, but here the purpose of the example leading to the question was perhaps pedagogical rather than simple. There's no obvious reason here why initialize shouldn't be a module procedure.
Instead, consider the example
interface
subroutine ext()
end subroutine
end interface
type mytype
contains
procedure(iface), nopass :: ext
end type
The external subroutine ext doesn't have a passed-object dummy (the binding has nopass) so doesn't need the module in which mytype is defined. This is a simplification.
Finally, as High Performance Mark comments, perhaps initialize needn't even be a binding name. Instead a "constructor" could be used:
type mytype
end mytype
interface mytype
procedure intialize_mytype
end interface
Details are left for the interested reader to find from other sources.
q)type variable
returns the type num of the arguement variable.
Is there a mapping that can produce the type char from a type num or do I have to create that dictionary myself?
Ideally something like
q)typeChar 1
i
You can use .Q.t.
q).Q.t abs type `test
"s"
q).Q.t abs type 5i
"i"
Edit: Or even better just use .Q.ty
This seems to return upper case for atoms and lower case for lists.
q).Q.ty `test
"S"
q).Q.ty `test`test2
"s"
One option is to use 'key' function :
Reference: http://code.kx.com/q/ref/metadata/#key
Wiki says: Given a simple list, returns the name of the type as a symbol:
So you can make function like:
q) tyeInChar:{key x,()}
q) typeInChar 1i // output `int
q) typeInChar "s" //output `char