Error SML NJ-Operator and Operand don't agree - ml

When I try to compile my ML Program ,I get an error saying:"Operator and Operand don't agree".
candidates.sml:78.8-78.40 Error: operator and operand don't agree [tycon mismatch]
operator domain: int * (int * 'Z * 'Y) list
operand: int * (int * real) list
in expression:
tr (n,candidates)
I understand the error but I can't find a solution.
The part of the code where I get the error is:
fun agonas fileName =
let
fun tr(n,[])=[]
| tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
val (n,l,candidates) = parse fileName
val cand = tr(n,candidates)
in
my_solution(l,cand)
end;
,where the candidates are related with the part below:
fun parse file =
let
(* a function to read an integer from an input stream *)
fun next_int input =
Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) input)
(* a function to read a real that spans till the end of line *)
fun next_real input =
Option.valOf (TextIO.inputLine input)
(* open input file and read the two integers in the first line *)
val stream = TextIO.openIn file
val n = next_int stream
val l = next_int stream
val _ = TextIO.inputLine stream
(* a function to read the pair of integer & real in subsequent lines *)
fun scanner 0 acc = acc
| scanner i acc =
let
val d = next_int stream
val (SOME v) = Real.fromString (next_real stream)
in
scanner (i - 1) ((d, v) :: acc)
end
in
(n, l, rev(scanner n []))
end;
fun my_solution ( n , l ,candidates ) = [2 ,3 ,5 ,4 ,6]
fun agonas fileName = my_solution ( parse fileName )
I would appreciate it if you could find the mistake.Thanks in advance.

The problem is that parse, using scanner, builds a list of pairs — (int * real) list — while tr expects to get a list of triples — (int * 'Z * 'Y) list.
Not knowing what tr is supposed to do, the quick and dirty fix would be to change
tr(n,((a,b,c)::d))=((n-a+1),b,c)::(tr(n,d))
into
tr(n,((a,b)::d))=((n-a+1),b)::(tr(n,d))
But that may be the wrong solution - it depends on what the code is supposed to do.
(Sometimes it helps to explicitly write out the types yourself - even before writing the code - instead of relying on type inference to catch the places where you need to do some more thinking.)

The error message says it all: the offending line calls trans, and that is a function that expects two arguments, the second being a list of triples. However, you are passing it a list of pairs instead (as produced by your scanner function).
You didn't show us the trans function, so I cannot be more specific about what the appropriate fix would be.

Related

List of digraphs in MATLAB

I am a beginner in MATLAB.
I have a function that takes an integer as input and returns a directed graph (digraph); I therefore have a list of integers L, and would like to create a list of digraphs derived from such integers.
I have a function create_graph(n) that returns such digraph.
What I am currently doing is:
Gs = [];
for i=1:length(L)
x = L(i);
G = create_graph(x);
Gs(end + 1) = G;
end
And it returns an error:
Unable to perform assignment because value of type 'digraph' is not convertible to 'double'.
Error in dummy_code (line 20)
Gs(end + 1) = G;
Caused by:
Error using double
Conversion to double from digraph is not possible.
Another error appear if I initialize a dummy digraph, that is:
Gs = [digraph([1,1;1,1])];
for i=1:length(L)
x = L(i);
G = create_graph(x);
Gs(end + 1) = G;
end
Error using indexing
Unsupported graph indexing.
What I would like to do is something close to the python code:
Gs = [create_graph(x) for x in L]

Fortran array input

I haven't done any Fortran programming for year and it seems I'm rather rusty now. So, I won't provide you with all my failed attempts but will humbly ask you to help me with the following.
I've got the following "input" file
1 5 e 4
A b & 1
c Z ; b
y } " N
t r ' +
It can have more columns and/or rows. I would now like to assign each of these ASCII characters to arrays x(i,j) so that I can process them further after ICHAR conversions. In this example i=1,4, j=1,5, but it can be any No depending on the input file. The simplest example
PROGRAM Example
integer :: i, j
CHARACTER, ALLOCATABLE, DIMENSION(:,:) :: A
READ *, A
ALLOCATE (A(i,j))
PRINT *, A
END PROGRAM Example
compiles (Example.f95) but
cat input | ./Example.f95
does not give any output.
I would greatly appreciate an advice on how to import the afore-mentioned strings into the program as x(i,j) terms of an array.
In Fortran, it's always best to know in advance how big your arrays need to be. I understand that in your case you can't know.
Assuming that your input is at least formatted correctly (i.e. the columns match up and have only a single space in between them), I've created a code that should in theory be able to read them in an arbitrary shape. (Not quite arbitrary, it assumes that there are fewer than 511 columns.)
It uses two ways:
It simply reads the first line in at once (1024 characters, hence the 511 limit on columns) then calculates from the length the number of columns
It then allocates an array with a guessed number of rows, and once it notices that the guess was too small, it creates a new allocation with double the number of rows. It then uses the move_alloc command to swap the allocations.
To find when it should end reading the values, it simply checks whether the read returns the IOSTAT_END error code.
Here's the code:
program read_input
use iso_fortran_env, only: IOSTAT_END
implicit none
character, dimension(:,:), allocatable :: A, A_tmp
character(len=1024) :: line ! Assumes that there are never more than 500 or so columns
integer :: i, ncol, nrow, nrow_guess
integer :: ios
character :: iom
! First, read the first line, to see how many columns there are
read(*, '(A)', iostat=ios, iomsg=iom) line
call iocheck('read first line', ios, iom)
ncol = (len_trim(line) + 1) / 2
! Let's first allocate memory for two rows, we can make it more later.
nrow_guess = 2
allocate(A(ncol, nrow_guess))
! Instead of standard input, we're reading from the line we read before.
read(line, '(*(A1,X))', iostat=ios, iomsg=iom) A(:, 1)
call iocheck('read first line into vals', ios, iom)
! Now loop over all the rows
nrow = 1
read_loop: do
if (nrow >= nrow_guess) then ! We have guessed too small.
! This is a bit convoluted, but the best
! way to increase the array shape.
nrow_guess = nrow_guess * 2
allocate(A_tmp(ncol, nrow_guess))
A_tmp(:, 1:nrow_guess/2) = A(:,:)
call move_alloc(A_tmp, A)
end if
read(*, '(*(A1,X))', iostat = ios, iomsg=iom) A(:, nrow+1)
if (ios == IOSTAT_END) exit read_loop ! We're done reading.
call iocheck('read line into vals', ios, iom)
nrow = nrow + 1
end do read_loop
! The last guess was probably too large,
! let's move it to an array of the correct size.
if (nrow < nrow_guess) then
allocate(A_tmp(ncol, nrow))
A_tmp(:,:) = A(:, 1:nrow)
call move_alloc(A_tmp, A)
end if
! To show we have all values, print them out.
do i = 1, nrow
print '(*(X,A))', A(:, i)
end do
contains
! This is a subroutine to check for IO Errors
subroutine iocheck(op, ios, iom)
character(len=*), intent(in) :: op, iom
integer, intent(in) :: ios
if (ios == 0) return
print *, "IO ERROR"
print *, "Operation: ", op
print *, "Message: ", iom
end subroutine iocheck
end program read_input
Edited to add
I had trouble with the special characters in your example input file, otherwise I'd just have made a read(*, *) A(:, nrow) -- but that messed the special characters up. That's why I chose the explicit (*(A1, X)) format. Of course that messes up when your characters don't start at the first position in the line.
You need to read the first line and determine how characters there in the line. Then read the entire file to determine the number of lines. Allocate the 2D array to hold characters. Then read the file and parse each line into the 2D array. There are more elegant ways of doing this, but here you go
program foo
implicit none
character(len=:), allocatable :: s
character, allocatable :: a(:,:)
integer fd, i, j, n, nr, nc
!
! Open file for reading
!
open(newunit=fd, file='tmp.dat', status='old', err=9)
!
! Determine number of characters in a row. Assumes all rows
! are of the same length.
!
n = 128
1 if (allocated(s)) then
deallocate(s)
n = 2 * n
end if
allocate(character(len=n) :: s)
read(fd,'(A)') s
if (len_trim(s) == 128) goto 1
s = adjustl(s)
n = len_trim(s)
deallocate(s)
!
! Allocate a string of the correct length.
!
allocate(character(len=n) :: s)
!
! Count the number of rows
!
rewind(fd)
nr = 0
do
read(fd,*,end=2)
nr = nr + 1
end do
!
! Read file and store individual characters in a(:,:)
!
2 rewind(fd)
nc = n / 2 + 1
allocate(a(nr,nc))
do i = 1, nr
read(fd,'(A)') s
do j = 1, nc
a(i,j) = s(2*j-1:2*j-1)
end do
end do
close(fd)
write(s,'(I0)') nc
s = '(' // trim(s) // '(A,1X))'
do i = 1, nr
write(*,s) a(i,:)
end do
stop
9 write(*,'(A)') 'Error: cannot open tmp.dat'
end program foo
Apparently, GOTO is verbotem, here. Here's an elegant solution.
program foo
implicit none
character, allocatable :: s(:), a(:,:)
integer fd, i, j, n, nr, nc
! Open file for reading
open(newunit=fd, file='tmp.dat', status='old', access='stream', err=9)
inquire(fd, size = n) ! Determine file size.
allocate(s(n)) ! Allocate space
read(fd) s ! Read the entire file
close(fd)
nr = count(ichar(s) == 10) ! Number of rows
nc = (count(ichar(s) /= 32) - nr) / nr ! Number of columns
a = reshape(pack(s, ichar(s) /= 32 .and. ichar(s) /= 10), [nc,nr])
a = transpose(a)
do i = 1, nr
do j = 1, nc
write(*,'(A,1X)',advance='no') a(i,j)
end do
write(*,*)
end do
stop
9 write(*,'(A)') 'Error: cannot open tmp.dat'
end program foo

Find the smallest subsequence of k distinct elements in a list

I am super new to sml. I am trying to write a simple code that takes an array of 5 positions with certain numbers and returns the length of the smallest subarray that contains all numbers. However I am getting many error messages that I cannot find in Google. Can anyone help me? The code is the following
fun Min x y = if x>y then return y else return x
local
val a = Array.array (3,0)
val cordela = Array.array(5,0)
val k=0
val front=0
val tail=0
val min=5
update(cordela,0,1)
update(cordela,1,3)
update(cordela,2,3)
update(cordela,3,2)
update(cordela,4,1)
in
fun loop front =
case k>3 of
if sub(a,sub(cordela,front)-1) = 0 then k=k+1 else()
update(a,sub(cordela,front)-1),sub(a,sub(cordela,front)-1)+1)
front = front +1
|
min= Min (front-tail) min
if sub(a,sub(cordela,front)-1) = 0 then k=k-1 else()
update(a,sub(cordela,front)-1),sub(a,sub(cordela,front)-1)-1)
tail=tail+1
if 5>front then loop front+1 else min
end
The error messages that I get are:
pl2.sml:16.13-16.15 Error: syntax error: replacing OF with LBRACKET
pl2.sml:18.36 Error: syntax error: inserting LPAREN
pl2.sml:20.4 Error: syntax error: replacing BAR with EQUALOP
pl2.sml:22.5 Error: syntax error: inserting LPAREN
pl2.sml:26.4 Error: syntax error: inserting LPAREN
pl2.sml:27.2 Error: syntax error found at END
Edit: I am trying to write this code in sml. It is written in c++
while(front < N){
if( k < K ){
if ( e[cordela[front]-1] == 0 ) k += 1;
e[cordela[front]-1] +=1;
front++ ;
}
else{
min = MIN(front - tail ,min);
if ( e[cordela[tail]-1] ==1 ) k -= 1;
e[cordela[tail]-1] -= 1;
tail++;
}
}
As John Coleman says, SML/NJ will not give very helpful error messages. You could try and install Moscow ML instead, since it gives better error messages. Unfortunately, there are some things wrong with this code at a syntactic level that makes it difficult for the compiler to give a meaningful error. Here are some hints to get the syntax right so that you can focus on the algorithm problems:
Don't use local, use let.
Match each ( with a ); you have too many )s.
Declare fun loop ... = ... inside let and in.
Once you've done that, a template for the function that solves your problem could look like:
fun smallest_subarray (needles : Array.array, haystack : Array.array) =
let
val ... = ...
fun loop ... = ...
in
if Array.length needles > Array.length haystack
then ...
else loop ...
end
What if there's no solution to the problem, what will the function return? ~1? NONE?
If you're trying to convert a C++ program to SML, try and include the function part in such a way that it's obvious what identifiers are arguments to the function, and try to name them logically; I have no idea what cordela, e and k are, or if N is a function of the size of the input array, or a constant.
Since an idiomatic solution in SML uses recursion (the function calling itself) rather than iteration (while), you are dealing with both a non-trivial algorithm problem and another paradigm. Try instead to solve a similar, but simpler problem where the algorithm is more trivial and apply the recursion paradigm.
For example, try and write a function that finds the position of an element in a sorted array using binary search:
fun find x arr =
let
fun loop ... = ...
in
loop ...
end
The loop function would take the search bounds (e.g. i and j) as argument and return either SOME i if x is found at position i, or NONE. You could extend this problem in the direction of your original problem by then trying to write a function that determines if an input array, needles, occurs in another input array, haystack, in the order given in needles. You could first assume that needles and haystack are sorted, and then assume that they're not.

matlab readfile with numbers

In general I'm defining a matlab fnction which takes the name of a file containing some numbers, one per line, reads the data in, and then returns the data in an array.
function x = readdata(filename)
This function takes the name of a file contained in the
% character array "filename", read in the data from it, and then
% return the resulting numbers in the 1-dimensional array x. The
% array x can be n x 1 or 1 x n, where n is the number of numbers
% in the data file.
%
% If the data file cannot be found, this function should print a
% warning (using the disp() function) and return x as an empty
% array. If the data file can be found but is empty or contains
% only comments (lines starting with the Matlab comment indicator %),
% this function should return an empty array x with no warning
% message.
%
%
%I'm not sure how to check if a file exist (while they are in same folder).
%I tried if exist(filename,'file') but this is not working
This is what I have now:
function x = readdata(file)
fid = fopen(file);
tline = fgets(fid);
while isnumeric(tline)
disp(tline)
tline = fgets(fid)
Thanks
I would start by taking a look at the documentation that you could find here for reading in line-by-line. It even gives a sample code that you could start with:
Reading Data Line-by-Line
MATLAB provides two functions that read lines from files and store them in
string vectors: fgetl and fgets. The fgets function copies the newline
character to the output string, but fgetl does not.
The following example uses fgetl to read an entire file one line at a time.
The function litcount determines whether an input literal string (literal)
appears in each line. If it does, the function prints the entire line preceded
by the number of times the literal string appears on the line.
function y = litcount(filename, literal)
% Search for number of string matches per line.
fid = fopen(filename);
y = 0;
tline = fgetl(fid);
while ischar(tline)
matches = strfind(tline, literal);
num = length(matches);
if num > 0
y = y + num;
fprintf(1,'%d:%s\n',num,tline);
end
tline = fgetl(fid);
end
fclose(fid);
You should be able to replace what is inside the while loop with what you are looking to do.
Of note is that the fgets and fgetl functions return character arrays (strings). Thus, you'll need to first check whether the line is a comment, and then, if not, convert the string to a numeric value using something along the lines of str2double.
As for checking existence of a file, exist(filename,'file') is definitely what you want. Its documentation is found here.
You should be able to do something like:
if ~exist(filename,'file')
% Do something... I suggest the warning function, disp could be used too...
warning('The file cannot be found!')
return
end

Standard ML programming, array function

In ML I have an array of chars! I am trying to find an array function in order to give the function the char #"T" and returns me the position of this element in array. I tried the find function and it doesn't work like that!
findi from the Array structure will do what you want. For an array of type 'a array, findi takes a (int * 'a) -> bool and a 'a array and returns an (int * 'a) option. So if you want to take a character and just return the character's position, you just need figure out the appropriate arguments to pass to findi and the appropriate way to interpret the result.
So for instance:
- fun findPos char = (Option.map (fn (i,_) => i)) o (Array.findi (fn (_,c) => c = char));
stdIn:2.65 Warning: calling polyEqual
val findPos = fn : ''a -> ''a array -> int option
- findPos #"c" (Array.fromList (explode "abcdef"));
val it = SOME 2 : int option
- findPos #"z" (Array.fromList (explode "abcdef"));
val it = NONE : int option

Resources