I have a Byte[] buffer that may contain one or multiple data frames, I need to read the first bytes to know how long the actual frame is.
This is a "non-working" version of what I want to do:
let extractFrame (buffer:byte[]) =
match buffer with
| [|head1;head2;head3;..|] when head2 < (byte)128 -> processDataFrame buffer head2
| <...others....>
| _ -> raise(new System.Exception())
Basically, I need to evaluate the first three bytes, and then call processDataFrame with the buffer and the actual length of the frame. Depending on the headers, the frame can be data, control, etc...
Can this be done with any kind of match (lists, sequences, ...etc...)? Or will I have to create another small array with just the length of the header?(I would like to avoid this).
If you want to use matching you could create active pattern (http://msdn.microsoft.com/en-us/library/dd233248.aspx):
let (|Head1|_|) (buffer:byte[]) =
if(buffer.[0] (* add condition here *)) then Some buffer.[0]
else None
let (|Head2|_|) (buffer:byte[]) =
if(buffer.[1] < (byte)128) then Some buffer.[1]
else None
let extractFrame (buffer:byte[]) =
match buffer with
| Head1 h1 -> processDataFrame buffer h1
| Head2 h2 -> processDataFrame buffer h2
........
| _ -> raise(new System.Exception())
I think that this might actually be easier to do using the plain if construct.
But as Petr mentioned, you can use active patterns and define your own patterns that extract specific information from the array. To model what you're doing, I would actually use a parameterized active pattern - you can give it the number of elements from the array that you need and it gives you an array with e.g. 3 elements back:
let (|TakeSlice|_|) count (array:_[]) =
if array.Length < count then None
else Some(array.[0 .. count-1])
let extractFrame (buffer:byte[]) =
match buffer with
| TakeSlice 3 [|head1;head2;head3|] when head2 < (byte)128 ->
processDataFrame buffer head2
| <...others....>
| _ -> raise(new System.Exception())
One disadvantage of this approach is that your pattern [|h1; h2; h3|] has to match to the length that you specified 3 - the compiler cannot check this for you.
Related
I need your help guys.
Im trying to learn and do a simple task in haskell, but it's still hard for me.
What im trying to do is: Read a line of numbers separated with whitespace, iterate over that list, check values, and if values are not zero add 1 otherwise -1. I was trying to do it watching some tutorials and other project code, but it just outputs a bunch of errors.
My code:
import System.Environment
import Control.Monad
import Text.Printf
import Data.List
import System.IO
solve :: IO ()
solve = do
nums <- map read . words <$> getLine
print (calculate nums)
calculate (x:xs) = x + check xs
check num
| num == 0 =
-1
| otherwise =
1
main :: IO ()
main = do
n <- readLn
if n /= 0
then do
printf "Case: "
solve
else main
Errors:
C:\Users\Donatas\Documents\haskell\la3.hs:9:21: error:
* Ambiguous type variable `b0' arising from a use of `read'
prevents the constraint `(Read b0)' from being solved.
Probable fix: use a type annotation to specify what `b0' should be.
These potential instances exist:
instance Read BufferMode -- Defined in `GHC.IO.Handle.Types'
instance Read Newline -- Defined in `GHC.IO.Handle.Types'
instance Read NewlineMode -- Defined in `GHC.IO.Handle.Types'
...plus 25 others
...plus six instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In the first argument of `map', namely `read'
In the first argument of `(.)', namely `map read'
In the first argument of `(<$>)', namely `map read . words'
|
9 | nums <- map read . words <$> getLine
| ^^^^
C:\Users\Donatas\Documents\haskell\la3.hs:10:9: error:
* Ambiguous type variable `a0' arising from a use of `print'
prevents the constraint `(Show a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Show HandlePosn -- Defined in `GHC.IO.Handle'
instance Show BufferMode -- Defined in `GHC.IO.Handle.Types'
instance Show Handle -- Defined in `GHC.IO.Handle.Types'
...plus 27 others
...plus 13 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In a stmt of a 'do' block: print (calculate nums)
In the expression:
do nums <- map read . words <$> getLine
print (calculate nums)
In an equation for `solve':
solve
= do nums <- map read . words <$> getLine
print (calculate nums)
|
10 | print (calculate nums)
| ^^^^^^^^^^^^^^^^^^^^^^
C:\Users\Donatas\Documents\haskell\la3.hs:12:1: error:
* Non type-variable argument in the constraint: Num [a]
(Use FlexibleContexts to permit this)
* When checking the inferred type
calculate :: forall a. (Eq a, Num [a], Num a) => [a] -> a
|
12 | calculate (x:xs) = x + check xs
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
To start with, I suggest you default to always writing type annotations. And before you start implementing anything, sketch out what the types of your program look like. For this program I suggest you start from:
main :: IO ()
solve :: String -> String
calculate :: [Int] -> Int
check :: Int -> Int
The names could also probably be improved to better convey what it is they're doing.
Note that there is only one function with type IO _. This serves to isolate the impure part of your program, which will make your life easier (e.g. testing, code reasoning, etc).
You're not far off. Just try reworking your code to fit into the above types. And be aware that you're missing a pattern in your calculate implementation ;)
If you inspect your code and follow the types, it is crystal-clear where the error is. Yes, you can add type annotations -- that is highly recommended -- but I find your code is so simple you could get away with just a bit of equational reasoning.
It starts with solve, it is easy to see that nums is of type Read a => [a], given that you split a string by words (i.e. [String]) and map read over it. So a list of as is what you give to calculate. As you know, a list is the disjoint sum between (1) the empty list ([]) and (2) a cons cell made of a head, an element of type a, and a tail, the rest of the list ((x:xs)).
First thing you notice is that the case of the empty list is missing; let's add it:
calculate [] = 0 -- I assume this is correct
On to the body of calculate and check. The latter clearly expects a number, you can be a bit more concise by the way:
check 0 = -1
check _ = 1
Now if you look at calculate, you see that you are calling check and passing it xs. What is xs? It is bound in the pattern (x:xs) which is how you uncons a cons cell. Clearly, xs is the tail of the cell and so a list itself. But check expects a number! The only number you can expect here is x, not xs. So let's change you code to
calculate (x:xs) = check x + ...
Your specifications state that you want to iterate over the list. That can only happen if you do something with xs. What can you do with it? The only answer to that is to call calculate recursively:
calculate (x:xs) = check x + calculate xs
... and with these changes, your code is fine.
I have an array of dataframes, all with the same colums. I would like to automatically plot a different line for a specific column for each of this dataframes. Something like:
plot(array[]$time, array[]$data)
is something like that possible, or do I have to loop each dataframe and add a line() for each dataframe?
Edit
I beg your pardon, in fact what I created is a list.
Basically I have two tables, connections that list different TCP conections informations:
src | src_port | dst | dst_port
and probes that contains timeseries data regarding packets and data transmitted:
timestamp | src | src_port | dst | dst_port | packets | bytes
So to plot the timeseries of all the different connections, I created a list of dataframe subsets, like that:
connection <- vector(mode='list', length = nrow(connections))
for (row in 1:nrow(connections)){
connection[[row]] <- subset(probes, src == connections[row, 'src'] & src_port == connections[row, 'src_port'] & dst == connections[row, 'dst'] & dst_port == connections[row, 'dst_port'])
}
What I want to obtain is to plot all these subset having in the x axis the timestamp and in the y axis the bytes, considering a different timesries for each connection.
I hope I better clarified the problem now.
Here's a reproducible example of plotting multiple dataframes extracted from a three-dimensional array. Notice the need to use "[[" to process the indices, and the fact that the default type of graphic for plot is points rather than lines. Could change that with type="l":
dfarray <- array( list(), c(2,3,4))
dfarray[[1,1,1]] <- data.frame(a=2:4, letters[2:4]) # need to use "[["
dfarray[[1,1,2]] <- data.frame(a=2:4, b=8:10)
dfarray[[1,1,3]] <- data.frame(a=2:4, b=10:12)
# Remember to make enough space to hold lines
png(); plot(b ~a, data=dfarray[[1,1,1]], ylim=c(5,12) )
for( x in 2:3) {lines( b~a, data=dfarray[[1,1,x]], col=x)}
dev.off()
This was quite interesting. I think we can generalise the for loop like this:
lapply(X = c(dfarray), FUN = function(x) {lines(x = x$a, y = x$b, ylim=c(5,12))}
I have an image stored as a very large List Int and I would like to turn them into a List Color However remember that rgb requires 3 arguments and rgba requires 4. So let's try:
toColor : List Int -> List Color
toColor x =
if List.isEmpty x then
[]
else
List.append ( rgba <| List.take 4 x ) ( toColor <| List.drop 4 x )
This definition is recursive. We chomp 4 numbers, create an rgb color and append the results. However if x is List Int we cannot write this:
rgba <| List.take 4 x
Here is the kind of error we get. rgb is expecting three numbers and instead it gets a list
71| rgb <| List.take 4 x
^^^^^^^^^^^^^
(<|) is expecting the right argument to be a:
Int
But the right argument is:
List a
I wonder that taking out the first element of a List Int returns a Maybe Int
head : List a -> Maybe a
> head [1,2,3,4]
Just 1 : Maybe.Maybe number
Here is a modification of rgb which turns 3 Maybe Int into a Color. Now, reading the image data, I think rgba is necessary but I just add one more.
rgb' : Maybe Int -> Maybe Int -> Maybe Int -> Color
rgb' a b c =
case a of
Nothing -> rgb 0 0 0
Just a' -> case b of
Nothing -> rgb 0 0 0
Just b' -> case c of
Nothing -> rgb 0 0 0
Just c' -> rgb a' b' c'
this started when I was translating this d3js example to Elm and I noticed it used some features which aren't currently supported in Elm. In particular ctx.getImageData() since you can't import and image to Canvas. So this is part of my make-shift solution.
It seems to me that you're looking for a really clean way to
Collapse a List Int into a List (List Int), where each child list has at most 3 or 4 members if you want to do rgb or rgba.
Pass each List Int into a function that will convert it using rgb, handling the case where there aren't enough Ints in the final entry.
For the first step, you can write a function called groupList:
groupsOf : Int -> List a -> List (List a)
groupsOf size list =
let
group =
List.take size list
rest =
List.drop size list
in
if List.length group > 0 then
group :: groupsOf size rest
else
[]
You can also get this functionality by using the greedyGroupsOf function from the elm-community/list-extra package.
For the second step, it'll be much cleaner to pattern match on the structure of the list value itself rather than using List.head and matching on Maybe.
rgbFromList : List Int -> Color
rgbFromList values =
case values of
r::g::b::[] ->
rgb r g b
_ ->
rgb 0 0 0
The first case will be matched when there are exactly 3 entries in the list, and everything else will fall through to handing 0s to rgb.
You can put all of these things together by doing the following:
toColor : List Int -> List Color
toColor x =
x
|> groupsOf 3
|> List.map rgbFromList
Alternatively, if instead of ending up with rgb 0 0 0 for invalid colors you want to exclude them entirely, you can use the List.filterMap function to prune out things you don't want. We can change rgbFromList to look like
rgbFromList : List Int -> Maybe Color
rgbFromList values =
case values of
r::g::b::[] ->
Just <| rgb r g b
_ ->
Nothing
and then call it like
toColor : List Int -> List Color
toColor x =
x
|> groupsOf 3
|> List.filterMap rgbFromList
Please be advised that since the groupsOf function here as well as greedyGroupsOf in elm-community/list-extra is recursive, it will fail for very large lists.
Edit: for very large lists
For very large lists it's easy to get into trouble with recursion. Your best bet is to fold over the list and manage some intermediate state while you're folding:
groupsOf : Int -> List a -> List (List a)
groupsOf size list =
let
update next state =
if (List.length state.current) == size then
{ current = [next], output = state.current :: state.output }
else
{ state | current = state.current ++ [next] }
result =
List.foldl update { current = [], output = [] } list
in
List.reverse (result.current :: result.output)
This works by folding over the list, which is an iterative process rather than recursive, and building up groups one at a time. The last step reverses the list because it will be constructed in reverse order in order to cons instead of doing costly appends once the output list begins to grow large. I don't expect this to overflow the stack, but it is likely that it will be very slow. In my opinion, your best option to get the outcome you are looking for in a reasonable amount of time is to write the groupsOf function in JavaScript using a for loop and then pass the result in through a port.
This recursive implementation should work without building the stack, because Elm has tail call optimisation. Each step takes three ints from the original list, and appends them to the list of colors. Recursion stops and returns the list of colors, when there are less than three elements in the original list.
It uses rgb, but can be easily modified to take 4 elements from the list.
It also reverses the order, so you might need to combine it with List.reverse.
import Color exposing (rgb, Color)
listColors : List Int -> List Color
listColors =
listColors' []
listColors' : List Color -> List Int -> List Color
listColors' colors ints =
case ints of
r :: g :: b :: rest ->
listColors' (rgb r g b :: colors) rest
_ ->
colors
I tried let stringArr = newvec(12); and then attempted to initialize each spot in the array as such: let stringArr!i = newvec(5); but that returns an error telling me I cannot do that. Is there anyone here who can help me with this dinosaur language?
You're stretching my memory a bit (to the extent of about three decades) but I seem to recall that let was used only for creating new local variables (also functions and possibly other things, but that's not really relevant for your question).
So the statement let stringArr = newvec(12) is valid in creating the new variable stringArr or, more precisely, a 12-cell anonymous vector and the stringArr variable holding the address of that vector.
However, let stringArr!i = newvec(5) is not valid, because stringArr!i isn't actually a new variable. It's simply the memory contents of cell number i in the already-existing stringArr vector.
In other words, the statement let stringArr = newvec(12) creates both the initial pointer cell and the second layer of pointers, which won't point anywhere useful yet:
+-----------+
| stringArr | ---+
+-----------+ | +-------------+
+--> | stringArr!0 | --> ?
+-------------+
| stringArr!1 | --> ?
+-------------+
: : :
+-------------+
| stringArr!N | --> ?
+-------------+
And, since the pointers already exist, you shouldn't be using let to set them.
It's similar in C in that you wouldn't write:
int xyzzy[10]; // Make array of ten elements.
int xyzzy[0] = 42; // Set first element to something.
since the second line isn't supposed to be defining a new variable, rather it's intent is simply to set one of the existing elements to a given value, done with xyzzy[0] = 42.
Hence the right way to do what you're trying to achieve in BCPL is to avoid using the let keyword for that second class of statements:
let stringArr = newvec(12) // Create new vector AND new variable,
// put vector address into cell for
// that variable.
stringArr!i := newvec(5) // Create new vector, put vector
// address into EXISTING cell.
The solution is sound but both of my versions of BCPL (Martin Richard's and Robert Nordier's obcpl) complain about newvec() and also require := rather than = in the second line. I got it working with:
let stringArr = getvec(12)
stringArr!i := getvec(12)
John Boutland
I'm trying to import a csv file in OCaml into an array. I do realise it's not the best fit for the langage and I'm not actually sure an array is the best structure, but anyway...
It's working fine, but I'm really uneasy about the way I did it.
let import file_name separator =
let reg_separator = Str.regexp separator in
let value_array = Array.make_matrix 1600 12 0. in
let i = ref 0 in
try
let ic = open_in file_name in
(* Skip the first line, columns headers *)
let _ = input_line ic in
try
while true; do
(* Create a list of values from a line *)
let line_list = Str.split reg_separator (input_line ic) in
for j = 0 to ((List.length line_list) - 1) do
value_array.(!i).(j) <- float_of_string (List.nth line_list j)
done;
i := !i + 1
done;
value_array
with
| End_of_file -> close_in ic; value_array
with
| e -> raise e;;
Basically, I read the file line by line, and I split each line along the separator. The problem is that this returns a list and thus the complexity of the following line is really dreadfull.
value_array.(!i).(j) <- float_of_string (List.nth line_list j)
Is there any way to do it in a better way short of recoding the whole split thing by myself?
PS : I haven't coded in Ocaml in a long time, so I'm quite unsure about the try things and the way I return the array.
Cheers.
On OCaml >=4.00.0, you can use the List.iteri function.
List.iteri
(fun j elem -> value_array.(!i).(j) <- float_of_string elem)
line_list
You can replace your for-loop with this code and it should work nicely (of course, you need to keep the ;).
On older version of OCaml, you can use List.iter with a reference you manually increment or, in a cleaner way, declare your own iteri.
Note that your code is not very safe, notably with respect to your file's size (in terms of number of lines and columns, for example). Maybe you should put your dimension parameters as function arguments for a bit of flexibility.
EDIT: for future readers, you can use the very simple ocaml-csv (through OPAM: opam install csv)