Haskell *** Exception: Prelude.read: no parse - parsing

Hi I am trying to complete CIS194 Spring 13 when I get the error message *** Exception: Prelude.read: no parse on one of my functions. The file that the function is in is called LogAnalysis.hs and the function is parseMessage, but the file also imports from Log.hs. Why am I geting this error message and how can I fix it?
Here is my code:
https://github.com/Adam-Morris/CIS194/tree/master/Homework-2

read is a function with type read :: Read a => String -> a. This means that read takes String as input and returns a value for some type a provided that a implements the Read type class. read has to know what specific type to return, and it can know that in one of two ways: either the type is given to it explicitly (e.g. read "123" :: Int or read "True" :: Bool) or it infers it from the context. In your case, read infers that it must return an Int because LogMessage expects an Int as its second parameter. So in this case the expression read [y] means: take the Char y, convert it into an one-element string, and then try to convert that to an Int, by parsing it. Now if y happens to contain a character that is not a decimal digit, it will fail (by throwing an exception) because it will not know how to covert it into an integer.
Now how can you deal with that issue? You must check that the input to read is ok before calling it. For example, you can check that y is a digit (using the appropriate function):
parseMessage (x:y:z)
| x == 'I' && isDigit y = LogMessage Info (read [y]) (unwords [z])
...
Alternatively, you can use readMaybe from Text.Read that is like read but it does not throw an exception if it fails, instead it returns a nothing value:
parseMessage (x:y:z)
| x == 'I', Just n <- readMaybe [y] = LogMessage Info n (unwords [z])

The problem is your input message format. You're reading a line as a string, then matching on the characters in the string (since a string is type alias for [Char]).
In your sample.log the first line (I 6 Completed armadillo processing) would be passed in as a string to parseMessage, and the parameters will take the following values:
x = 'I'
y = ' ' --single white space character
z = "6 Completed armadillo processing"
read gets the white space character and throws *** Exception: Prelude.read: no parse
In order to get the values, you could do the following:
parseMessage :: String -> LogMessage
parseMessage msg =
case words msg of
"I":y:z -> LogMessage Info (read y :: TimeStamp) (unwords z)
"W":y:z -> undefined
"E":y:z -> undefined
_ -> undefined
This way the first two valid words (MessageType and TimeStamp in this case) can be extracted easily.

Related

How to allocate a derived type-parameterized (Fortran 2003)?

Am testing the derived type parameterized. the array in the derived type contains a scalar expression .
For example :
integer :: a(n+2)
I used the intel compiler version 18.0 . It works perfectly . But with gfortran 8.3 am having an internal compiler error
For example:
public
type mytab(n)
integer, len :: n
integer :: tab1(n)
integer :: tab2(n*2)
end type mytab
contains
subroutine create(pt1, n)
type(mytab(:)),allocatable, intent(out) :: pt1
integer, intent(in) :: n
allocate (mytab(n)::pt1)
end subroutine
The allocation works only for tab1 and not tab2
this is what a get as an error.
allocate (mytab(n)::pt1)
internal compiler error: in gfc_conv_expr_op, at fortran/trans-expr.c:3498
0x5c5fa9 gfc_conv_expr_op
../../gcc/fortran/trans-expr.c:3498
0x5c5fa9 gfc_conv_expr(gfc_se*, gfc_expr*)
../../gcc/fortran/trans-expr.c:7999
0x704b17 gfc_conv_expr_val(gfc_se*, gfc_expr*)
../../gcc/fortran/trans-expr.c:8056
0x704c30 gfc_conv_expr_type(gfc_se*, gfc_expr*, tree_node*)
../../gcc/fortran/trans-expr.c:8070
0x6e3401 structure_alloc_comps
../../gcc/fortran/trans-array.c:9129
0x6e6260 gfc_allocate_pdt_comp(gfc_symbol*, tree_node*, int, gfc_actual_arglist*)
../../gcc/fortran/trans-array.c:9405
0x73e4cd gfc_trans_allocate(gfc_code*)
../../gcc/fortran/trans-stmt.c:6599
0x6cf5e7 trans_code
../../gcc/fortran/trans.c:2001
0x6f5dbb gfc_generate_function_code(gfc_namespace*)
../../gcc/fortran/trans-decl.c:6515
0x6d2fe9 gfc_generate_module_code(gfc_namespace*)
../../gcc/fortran/trans.c:2227
0x68612b translate_all_program_units
../../gcc/fortran/parse.c:6112
0x68612b gfc_parse_file()
../../gcc/fortran/parse.c:6328
0x6cca5f gfc_be_parse_file
../../gcc/fortran/f95-lang.c:204
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

args[] in Main for F#

Here is some code In F# that I tried following the book Programming F# byChris Smith:
(*
Mega Hello World:
Take two command line parameters and then print
them along with the current time to the console.
*)
open System
[<EntryPoint>]
let main (args : string[]) =
if args.Length <> 2 then
failwith "Error: Expected arguments <greeting> and <thing>"
let greeting, thing = args.[0], args.[1]
let timeOfDay = DateTime.Now.ToString("hh:mm tt")
printfn "%s, %s at %s" greeting thing timeOfDay
// Program exit code
0
main(["asd","fgf"]) |> ignore
There is an error in main that says: This expression was expected to have type 'String[]' but here ahs type "a list'. But string[] is an array of string. SO I don't understand my error.
string[] is indeed an array of strings, but ["asd", "fgf"] is not - it's a list, which is why you get that error.
To create an array instead, use [|"asd"; "fgf"|] (note that, both in lists and arrays, ; is used as a separator - , creates tuples).
In addition, you can't have code after a function marked as EntryPoint. And even if you could, calling that function makes no sense as it will already be called automatically with the command line arguments - that's the point of the EntryPoint attribute.

confusion regarding erlang maps, lists and ascii

This code is an excerpt from this book.
count_characters(Str) ->
count_characters(Str, #{}).
count_characters([H|T], #{ H => N }=X) ->
count_characters(T, X#{ H := N+1 });
count_characters([H|T], X) ->
count_characters(T, X#{ H => 1 });
count_characters([], X) ->
X.
So,
1> count_characters("hello").
#{101=>1,104=>1,108=>2,111=>1}
What I understand from this is that, count_characters() takes an argument hello, and place it to the first function, i.e count_characters(Str).
What I don't understand is, how the string characters are converted into ascii value without using $, and got incremented. I am very new to erlang, and would really appreciate if you could help me understand the above. Thank you.
In erlang the string literal "hello" is just a more convenient way of writing the list [104,101,108,108,111]. The string format is syntactic sugar and nothing erlang knows about internally. An ascii string is internally string is internally stored as a list of 32-bit integers.
This also becomes confusing when printing lists where the values happen to be within the ascii range:
io:format("~p~n", [[65,66]]).
will print
"AB"
even if you didn't expect a string as a result.
As said previously, there is no string data type in Erlang, it uses the internal representation of an integer list, so
"hello" == [$h,$e,$l,$l,$o] == [104|[101|[108|[108|[111|[]]]]]]
Which are each a valid representation of an integer list.
To make the count of characters, the function use a new Erlang data type: a map. (available only since R17)
A map is a collection of key/value pairs, in your case the keys will be the characters, and the values the occurrence of each characters.
The function is called with an empty map:count_characters(Str, #{}).
Then it goes recursively through the list, and for each head H, 2 cases are posible:
The character H was already found, then the current map X will match with the pattern #{ H => N } telling us that we already found N times H, so we continue the recursion with the rest of the list and a new map where the value associated to H is now N+1: count_characters(T, X#{ H := N+1 }.
The character H is found for the first time, then we continue the recursion with the rest of the list and a new map where the key/value pair H/1 is added: count_characters(T, X#{ H => 1 }).
When the end of the list is reached, simply return the map: count_characters([], X) -> X.

F# odd pattern matching issues

While writing some code yesterday, I ran into two odd problems, which neither me nor my functional programming oriented friend could figure out. We have looked at it for quite some time, and researched it on the net, but we were not able to find any answers anywhere, so here goes:
The issue is that in this code:
First weird problem:
let outer1 (bs : byte array) =
let rec inner (bs : byte array) (bacc : byte array) (i : int) =
match i with
| bs.Length -> bacc // <--- Error: bs is not recognized. Why?
| _ -> bacc.[i] <- bs.[i]
inner bs bacc (i + 1)
inner bs (Array.zeroCreate bs.Length) 0
The problem here is: FS0039: The namespace or module 'bs' is not defined.
How can this be? bs is in the function signature after all. Moreover, defining a new value with let bsLength = bs.Length works right before the match. But by doing so I see a new oddity:
let outer2 (bs : byte array) =
let rec inner (bs : byte array) (bacc : byte array) (i : int) =
let bsLength = bs.Length
match i with
| bsLength -> bacc
| _ -> bacc.[i] <- bs.[i] // <--- Warning: Rule never matched. Why?
inner bs bacc (i + 1)
inner bs (Array.zeroCreate bs.Length) 0
Here the problem is a warning that says: warning FS0026: This rule will never be matched.
I don't get that at all. i and the length of the array has no relation to each other. If I write an integer (for instance 10) instead of bsLength, the warning disappears.
Both your problems stem from the expectation that pattern matching allows using values and literals interchangeably. No, it does not. Pattern Matching (F#) topic on MSDN gives a good overview of supported pattern types and precedence rules of their application. The major principle simplifying a lengthy description there is: you cannot match a value unless this value is a literal, or identifier (a case value of a discriminated union, an exception label, or an active pattern case).
In your first problem point compiler treats bs.Length not as a property Length of array bs as you expect, but as a literal or identifier Length from non-existing module or namespace bs; as John Palmer pointed in his answer you may achieve the expected behavior by using variable pattern with a guard statement. A sample of legitimate use of the pattern matching expression resembling yours would be:
module bs =
[<Literal>]
let Length = 100
//.............................
let v = 100;
let s = match v with
| bs.Length -> "matched"
| _ -> "not matched";;
val s : string = "matched"
The second problem point is treated by compiler as variable pattern, and bsLength is assigned a value of i instead of values being compared, as you expected; second matching rule does not have chances to kick in.
The match statement doesn't work like you think it does - the correct syntax is
match i with
| t when t = bs.Length
In the second case, you actually create a new variable called bsLength which hides the definition of the earlier bsLength and matches all integers, so you get the rule never matched warning.

Haskell - Reading a file and passing data as arguments to function

I'm trying to get some data from a file, then parse it and pass it to another function as an argument.
data LogLine = LogLine {
name :: String
, args1 :: String
, args2 :: String
, constant :: String
} deriving (Ord, Show, Eq)
main = do
file <- readFile "foo"
let result = (parse final "Input" file) --Parses the file into the LogLine datatype
let firstargs = getFirstArgs result --Get the first argument out of the datatype
let secondargs = getSecondArgs result --Get the second argument out of the datatype
let constant = getConstant result --Get the constant out of the datatype
createGraph firstargs secondargs constant --THIS IS THE PROBLEM
The problem is that whenever I try to read-in a file it becomes an (IO String) and I always have to carry the IO whatever I do.
the createGraph function is declared as
createGraph :: String -> String -> String -> Argument
but whenever I try to execute the last statement it complains:
Couldn't match expected type `IO a0' with actual type `Argument'
In the return type of a call of `createGraph'
I'm not allowed to change the return type of the createGraph function, because it's a part of a large framework that I need to feed the arguments to.
What are the ways of dealing with this?
Why would you want to do that?
The only way to get your value into the IO monad is by using return.
You can either wrap the call to createGraph into another function like
returnGraph a b c = return $ createGraph a b c
or just use another let binding and use your value when you need it.
I can't figure out what you want to do there.Please give us more details as in what do you want to do with the returned value.
--
From what i understand from your comment you just need to return the argument so the only thing you have to do is return $ createGraph firstargs secondargs constant and rename the function from main to something else because main must have type IO ().
The problem is that whenever I try to read-in a file it becomes an (IO String) and I always have to carry the IO whatever I do.
I don't think this is the real problem. The problem is that main has a return type of IO() which is the result of the last line executed. In this case, that means the createGraph call which results in an Argument. This is why you get the type error, which has nothing to do with the IO String that is read from the file.
One solution is to simply return the result of createGraph at the end of main:
return $ createGraph firstargs secondargs constant

Resources