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

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

Related

I don't understand this map tuple key compilation error, in F#

Here is a function:
let newPositions : PositionData list =
positions
|> List.filter (fun x ->
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
| false, _ ->
// if we don't know the position, it's new
true
| true, p when x.UpdateTime > p.UpdateTime ->
// it's newer than the version we have, it's new
true
| _ ->
false
)
it compiles at expected.
let's focus on two lines:
let key = (x.Instrument, x.Side)
match brain.Positions.TryGetValue key with
brain.Positions is a Map<Instrument * Side, PositionData> type
if I modify the second line to:
match brain.Positions.TryGetValue (x.Instrument, x.Side) with
then the code will not compile, with error:
[FS0001] This expression was expected to have type
'Instrument * Side'
but here has type
'Instrument'
but:
match brain.Positions.TryGetValue ((x.Instrument, x.Side)) with
will compile...
why is that?
This is due to method call syntax.
TryGetValue is not a function, but a method. A very different thing, and a much worse thing in general. And subject to some special syntactic rules.
This method, you see, actually has two parameters, not one. The first parameter is a key, as you expect. And the second parameter is what's known in C# as out parameter - i.e. kind of a second return value. The way it was originally meant to be called in C# is something like this:
Dictionary<int, string> map = ...
string val;
if (map.TryGetValue(42, out val)) { ... }
The "regular" return value of TryGetValue is a boolean signifying whether the key was even found. And the "extra" return value, denoted here out val, is the value corresponding to the key.
This is, of course, extremely awkward, but it did not stop the early .NET libraries from using this pattern very widely. So F# has special syntactic sugar for this pattern: if you pass just one parameter, then the result becomes a tuple consisting of the "actual" return value and the out parameter. Which is what you're matching against in your code.
But of course, F# cannot prevent you from using the method exactly as designed, so you're free to pass two parameters as well - the first one being the key and the second one being a byref cell (which is F# equivalent of out).
And here is where this clashes with the method call syntax. You see, in .NET all methods are uncurried, meaning their arguments are all effectively tupled. So when you call a method, you're passing a tuple.
And this is what happens in this case: as soon as you add parentheses, the compiler interprets that as an attempt to call a .NET method with tupled arguments:
brain.Positions.TryGetValue (x.Instrument, x.Side)
^ ^
first arg |
second arg
And in this case it expects the first argument to be of type Instrument * Side, but you're clearly passing just an Instrument. Which is exactly what the error message tells you: "expected to have type 'Instrument * Side'
but here has type 'Instrument'".
But when you add a second pair of parens, the meaning changes: now the outer parens are interpreted as "method call syntax", and the inner parens are interpreted as "denoting a tuple". So now the compiler interprets the whole thing as just a single argument, and all works as before.
Incidentally, the following will also work:
brain.Positions.TryGetValue <| (x.Instrument, x.Side)
This works because now it's no longer a "method call" syntax, because the parens do not immediately follow the method name.
But a much better solution is, as always, do not use methods, use functions instead!
In this particular example, instead of .TryGetValue, use Map.tryFind. It's the same thing, but in proper function form. Not a method. A function.
brain.Positions |> Map.tryFind (x.Instrument, x.Side)
Q: But why does this confusing method even exist?
Compatibility. As always with awkward and nonsensical things, the answer is: compatibility.
The standard .NET library has this interface System.Collections.Generic.IDictionary, and it's on that interface that the TryGetValue method is defined. And every dictionary-like type, including Map, is generally expected to implement that interface. So here you go.
In future, please consider the Stack Overflow guidelines provided under How to create a Minimal, Reproducible Example. Well, minimal and reproducible the code in your question is, but it shall also be complete...
…Complete – Provide all parts someone else needs to reproduce your
problem in the question itself
That being said, when given the following definitions, your code will compile:
type Instrument() = class end
type Side() = class end
type PositionData = { Instrument : Instrument; Side : Side; }
with member __.UpdateTime = 0
module brain =
let Positions = dict[(Instrument(), Side()), {Instrument = Instrument(); Side = Side()}]
let positions = []
Now, why is that? Technically, it is because of the mechanism described in the F# 4.1 Language Specification under §14.4 Method Application Resolution, 4. c., 2nd bullet point:
If all formal parameters in the suffix are “out” arguments with byref
type, remove the suffix from UnnamedFormalArgs and call it
ImplicitlyReturnedFormalArgs.
This is supported by the signature of the method call in question:
System.Collections.Generic.IDictionary.TryGetValue(key: Instrument * Side, value: byref<PositionData>)
Here, if the second argument is not provided, the compiler does the implicit conversion to a tuple return type as described in §14.4 5. g.
You are obviously familiar with this behaviour, but maybe not with the fact that if you specify two arguments, the compiler will see the second of them as the explicit byref "out" argument, and complains accordingly with its next error message:
Error 2 This expression was expected to have type
PositionData ref
but here has type
Side
This misunderstanding changes the return type of the method call from bool * PositionData to bool, which consequently elicits a third error:
Error 3 This expression was expected to have type
bool
but here has type
'a * 'b
In short, your self-discovered workaround with double parentheses is indeed the way to tell the compiler: No, I am giving you only one argument (a tuple), so that you can implicitly convert the byref "out" argument to a tuple return type.

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.

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

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.

In F#, is it possible to pass a reference to a mutable, defaulted value as a parameter?

For the Froto project (Google Protobuf in F#), I am trying to update the deserialization code from using 'a ref objects to passing values byref<'a>, for performance.
However, the code below fails on the hydrator &element field line:
type Field = TypeA | TypeB | Etc
let hydrateRepeated
(hydrator:byref<'a> -> Field -> unit)
(result:byref<'a list>)
(field:Field) =
let mutable element = Unchecked.defaultof<'a>
hydrator &element field
result <- element :: result
error FS0421: The address of the variable 'element' cannot be used at this point
Is there anything I can do to get this code to work without changing the signature of the hydrator parameter?
I'm very aware that I could use hydrator:'a ref -> Field -> unit and get things to work. However, the goal is to support deserializing into record types without needing to create a bunch of ref objects on the heap every time a record is deserialize.
Note that the following code is perfectly legal and has the same signature as the hydrator function declaration, above, so I'm unclear on what the problem is.
let assign (result:byref<'a>) (x:'a) =
result <- x
let thisWorks() =
let mutable v = Unchecked.defaultof<int>
assign &v 5
printfn "%A" v
I'll try to clarify what I was saying in my comments. You're right that your definition of assign is perfectly fine, and it appears to have the signature byref<'a> -> 'a -> unit. However, if you look at the resulting assembly, you'll find that the way it's compiled at the .NET representation level is:
Void assign[a](a ByRef, a)
(that is, it's a method that takes two arguments and doesn't return anything, not a function value that takes one argument and returns a function that takes the next argument and returns a value of type unit - the compiler uses some additional metadata to determine how the method was actually declared).
The same is true of function definitions that don't involve byref. For instance, assume you've got the following definition:
let someFunc (x:int) (y:string) = ()
Then the compiler actually creates a method with the signature
Void someFunc(Int32, System.String)
The compiler is smart enough to do the right thing when you try to use a function like someFunc as a first class value - if you use it in a context where it isn't applied to any arguments, the compiler will generate a subtype of int -> string -> unit (which is FSharpFunc<int, FSharpFunc<string, unit>> at the .NET representation level), and everything works seamlessly.
However, if you try to do the same thing with assign, it won't work (or shouldn't work, but there are several compiler bugs that may make it seem like certain variations work when really they don't - you might not get a compiler error but you may get an output assembly that is malformed instead) - it's not legal for .NET type instantiations to use byref types as generic type arguments, so FSharpFunc<int byref, FSharpFunc<int, unit>> is not a valid .NET type. The fundamental way that F# represents function values just doesn't work when there are byref arguments.
So the workaround is to create your own type with a method taking a byref argument and then create subtypes/instances that have the behavior you want, sort of like doing manually what the compiler does automatically in the non-byref case. You could do this with a named type
type MyByrefFunc2<'a,'b> =
abstract Invoke : 'a byref * 'b -> unit
let assign = {
new MyByrefFunc2<_,_> with
member this.Invoke(result, x) =
result <- x }
or with a delegate type
type MyByrefDelegate2<'a,'b> = delegate of 'a byref * 'b -> unit
let assign = MyByrefDelegate2(fun result x -> result <- x)
Note that when calling methods like Invoke on the delegate or nominal type, no actual tuple is created, so you shouldn't be concerned about any extra overhead there (it's a .NET method that takes two arguments and is treated as such by the compiler). There is the cost of a virtual method call or delegate call, but in most cases similar costs exist when using function values in a first class way too. And in general, if you're worried about performance then you should set a target and measure against it rather than trying to optimize prematurely.

Write f# Function that takes parameterized constructor

I want to write a function that creates an object from a data stream, e.g.
let nxL<'T when 'T : (new : unit -> 'T)> (sr:StreamReader) =
let line = sr.ReadLine()
if line <> null then
Some(new 'T(line))
else
None
However, this doesn't work as it fails with:
Calls to object constructors on typed parameters cannot be given arguments.
Since a constructor is a function and F# is a functional language this makes no sense to me. Does anyone know how to create a function that takes a type as an argument and returns new instances?
Although passing a function, as #scrwtp suggested, is a good aproach, what you want is possible:
let inline nxL (sr:StreamReader) =
let line = sr.ReadLine()
if line <> null then
Some(^a : (new : string -> ^a) line)
else
None
You could create an object given a type using Activator.CreateInstance, but I don't feel it's strictly necessary from the code snippet you posted. Wouldn't passing a regular function that takes a string and returns an object of the desired type work for you? Sort of a factory function, if you care. Like this:
let nxL<'T> (cons: string -> 'T) (sr:StreamReader) : 'T option =
let line = sr.ReadLine()
if line <> null then
Some (cons line)
else
None
What's more, you could actually drop all the type annotations on it apart from StreamReader, and it will be inferred to be generic (leaving them on so it's clear what goes on in the snippet).

Resources