Given the following list
List Records
where Record is
type Record
= RecordA A
| RecordB B
and A and B are type aliases with pos field:
type alias A =
{ pos : Maybe Int
, type : Char
}
how would I create a new list that numbers subsequent A and B records? I want to have pos = 1 in the first A record, pos = 2 in the second A record, pos = 1 in the first B record, etc. (The original list comes without numbers in the pos field.)
This is a solution for a language that allows mutation.
let countA = 0;
let countB = 0;
for (el of my_array) {
el.pos = (el.type == 'A') ? ++countA : ++countB;
}
You can convert any iterative algorithm using mutable variables into a recursive one that don't quite easily by just making the mutable variables function arguments:
enumerate : List Record -> Int -> Int -> List Record
enumerate list countA countB =
case list of
[] ->
[]
(RecordA el) :: rest ->
RecordA { el | pos = Just countA } :: enumerate rest (countA + 1) countB
(RecordB el) :: rest ->
RecordB { el | pos = Just countB } :: enumerate rest countA (countB + 1)
This is not tail recursive however, and will therefore overflow the stack on larger lists. It's also a bit inconvenient to have to specify the initial counts every time we use this. We can solve both by using an inner function and adding an accumulator argument to it:
enumerate : List Record -> List Record
enumerate list =
let
aux els acc posA posB =
case list of
[] ->
acc
(RecordA el) :: rest ->
aux rest (RecordA { el | pos = Just posA } :: acc) (posA + 1) posB
(RecordB el) :: rest ->
aux rest (RecordB { el | pos = Just posB } :: acc) posA (posB + 1)
in
aux list [] 0 0
You seem to have some deeper data modeling issues here though, but it also doesn't look like your actual types, so hopefully you'll figure that out eventually too. This should at least get you a bit closer.
Lazy response: A map expression might, in essence, do what you want. I haven't checked this thoroughly because I was as well too lazy for the boilerplate to make it actually compile in an ellie though:
List.map (\n -> RecordA (A(Just n) 'a')) (List.range 1 5)
If I get you correctly, you have a list containing both A and B types? Then you might want to pattern match on the types in the function that is mapped over the list (the (\n -> RecordA (A(Just n) 'a')) part), maybe construct two lists and zip them together. But as #glennsl already said, the design leaves some questions open.
Related
I'm working on a problem where they ask us to write a function to determine if a matrix is square (n by n, for any n >= 0) with OCaml
I have a type matrix already defined
type matrix = float list list
Also I previously have a function that works to determine the length of a list
let rec length (l : 'a list): int =
match l with
| [] -> 0
| _ :: xs' -> 1 + length xs'
Right now I'm thinking about writing a helper function which checks if the length of all rows are equal
let rec check_row_equal (m : matrix): bool =
match m with
| [] -> true
| h1 :: h2 :: t ->
if length h1 <> length h2 then false
else check_row_equal (h2 :: t)
But when I ran this function in utop, it says Match_failure ("//toplevel//", 2, 2). If I have this helper function running correctly, my thought for my next function would be
let rec is_square (m : matrix): bool =
let l = length m in
if check_row_equal m == false then false
else if (l != the length of one of the rows) then false
else true
I haven't figured out how to calculate the length of the row, maybe another helper function like
let row_length (m : matrix): int =
match m with
| [] -> 0
| h :: t -> length h
But again, I need help with the check_row_equal function, please help me to fix that, thank u!
let rec check_row_equal (m : matrix): bool =
match m with
| [] -> true
| h1 :: h2 :: t ->
if length h1 <> length h2 then false
else check_row_equal (h2 :: t)
You're getting a match error because you have a case for an empty list, and a list with two or more elements, but not a list with one element. Presumably if there is only one row, this should return true.
Incorporating this and simplifying the code a bit.
let rec check_row_equal (m : matrix): bool =
match m with
| [] | [_] -> true
| h1 :: (h2 :: _ as tl) ->
length h1 = length h2 && check_row_equal tl
You don't say what it means specifically to check whether a matrix is square. I'll assume you want to check the lengths of all the contained lists to make sure they're the same, and this should also be the same as the length of the outer list.
Here are a couple of comments:
Your length function works correctly in the abstract, but it doesn't work for the normal kind of OCaml list. In OCaml, the empty list (the final tail of every list) looks like [] and Cons (a, b) looks like a :: b. Maybe your code is supposed to work with a custom list type, but then it's confusing to name it list, like the normal OCaml list.
You already have a function length that visits every element of a list and calculates an answer. You need a function just like this except that each element of the list is another list, and you want to determine whether the lengths of these are all the same. Just as your length function gets a new result by adding 1 to the returned result, you can figure out an operation that tracks whether the lists have all been the same length so far and, if so, what that length was.
I hope this helps. I don't want to write code for you because this is an assignment.
My goal is to take a char list like:
['a'; 'a'; 'a'; 'a'; 'a'; 'b'; 'b'; 'b'; 'a'; 'd'; 'd'; 'd'; 'd']
Count the number of repeated characters and transform it into a (int * char) list like this:
[(5, 'a'); (3, 'b'); (1, 'a'); (4, 'd')]
I am completely lost and also am very very new to OCaml. Here is the code I have rn:
let to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
let count = int 0 in
while t <> [] do
if h = t then
count := count + 1;
done;
I am struggling on how to check the list like you would an array in C or Python. I am not allowed to use fold functions or map or anything like that.
Edit: Updated code, yielding an exception on List.nth:
let rec to_run_length (lst : char list) : (int * char) list =
let n = ref 0 in
match lst with
| [] -> []
| h :: t ->
if h = List.nth t 0 then n := !n + 1 ;
(!n, h) :: to_run_length t ;;
Edit: Added nested match resulting in a function that doesn't work... but no errors!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| [] -> []
| (n, c) :: tail ->
if h <> c then to_run_length t
else (n + 1, c) :: tail ;;
Final Edit: Finally got the code running perfect!
let rec to_run_length (lst : char list) : (int * char) list =
match lst with
| [] -> []
| h :: t ->
match to_run_length t with
| (n, c) :: tail when h = c -> (n + 1, h) :: tail
| tail -> (1, h) :: tail ;;
One way to answer your question is to point out that a list in OCaml isn't like an array in C or Python. There is no (constant-time) way to index an OCaml list like you can an array.
If you want to code in an imperative style, you can treat an OCaml list like a list in C, i.e., a linked structure that can be traversed in one direction from beginning to end.
To make this work you would indeed have a while statement that continues only as long as the list is non-empty. At each step you examine the head of the list and update your output accordingly. Then replace the list with the tail of the list.
For this you would want to use references for holding the input and output. (As a side comment, where you have int 0 you almost certainly wanted ref 0. I.e., you want to use a reference. There is no predefined OCaml function or operator named int.)
However, the usual reason to study OCaml is to learn functional style. In that case you should be thinking of a recursive function that will compute the value you want.
For that you need a base case and a way to reduce a non-base case to a smaller case that can be solved recursively. A pretty good base case is an empty list. The desired output for this input is (presumably) also an empty list.
Now assume (by recursion hypothesis) you have a function that works, and you are given a non-empty list. You can call your function on the tail of the list, and it (by hypothesis) gives you a run-length encoded version of the tail. What do you need to do to this result to add one more character to the front? That's what you would have to figure out.
Update
Your code is getting closer, as you say.
You need to ask yourself how to add a new character to the beginning of the encoded value. In your code you have this, for example:
. . .
match to_run_length t with
| [] -> []
. . .
This says to return an empty encoding if the tail is empty. But that doesn't make sense. You know for a fact that there's a character in the input (namely, h). You should be returning some kind of result that includes h.
In general if the returned list starts with h, you want to add 1 to the count of the first group. Otherwise you want to add a new group to the front of the returned list.
I have a problem, namely, I would like to turn the following code into a recursive function for adding even list elements, but unfortunately I do not know how much ...
let even = List.filter(fun x -> x%2=0)[1..100]
let sum = List.length even
printfn "Even: %A sum: %d " even sum
Thank you for any help!
You can use pattern matching to check if the first element in your list is even,
and if so, to add it into accumulator list and call the same method on the rest of the list. In case the element is odd - just call the same method for the rest of the list without adding anything to accumulator. When list is empty - return the accumulator and you will have list of just even numbers.
let rec getEven (input : int list) (acc: int list) =
match input with
| head :: tail when head % 2 = 0 -> (getEven tail (head :: acc))
| head :: tail when head % 2 = 1 -> (getEven tail (acc))
| _ -> acc
let even = getEven [1..10] []
let sum = List.sum even
Function above will produce:
val getEven : input:int list -> acc:int list -> int list
val even : int list = [10; 8; 6; 4; 2]
val sum : int = 30
P.S. to calculate sum of the elements, you should use List.sum instead of List.length that will return you the number of elements in list.
Also note, that you can calculate sum of even elements in getEven function, storing not the list of even elements, but their sum.
I'm new to Haskell and I'm trying to write simple functions to get myself used to the syntax, I want to write my own function for adding a certain element to a list at a specific index. Here's what I wrote in Atom (my text editor):
addElem :: a->[a]->Int->[a]
addElem elem list index
| index <= 0 = elem:list
| index < (length list) = a ++ (elem:b) where a = take index list; b = drop index list
| otherwise = list
The idea is that it won't freak out as long as index is an Int and elem is of the same type as the elements of list, but when I try to load this into ghci I get "parse error on `|'." Do I need to constrain the types of the arguments? I'm reading Learn You A Haskell but I haven't gotten to the part where they fully explain how the indentations work, so my error might also be there.
where blocks need to occur at the end of the whole function, and are shared amongst all the cases. You probably meant to use a let:
addElem :: a -> [a] -> Int -> [a]
addElem elem list index
| index <= 0 = elem:list
| index < (length list) = let a = take index list; b = drop index list in a ++ (elem:b)
| otherwise = list
Also, note that let could be written more concisely as let (a,b) = splitAt index list in .... splitAt is also in the Prelude. Of course, you could also just move the where block to the end of the function (Haskell's laziness makes this easy to reason about).
addElem :: a -> [a] -> Int -> [a]
addElem elem list index
| index <= 0 = elem:list
| index < (length list) = a ++ (elem:b)
| otherwise = list
where
a = take index list
b = drop index list
Personally, I like this less because it suggests that a and b may be used elsewhere in the function.
Section 4.4.3 of the 2010 Haskell Report goes into more detail on where where is allowed.
Hello i resolved problem with ealier task.
Now if i have for example list = [ 2; 3; 2 ; 6 ] want to translate it like this [2;5;7;13].
I declared x as my first element and xs as my rest and used List.scan . Idea below
(fun x n -> x + n) 0
but this make something like this
val it : int list = [0; 2; 5; 7; 13]
How to rewrite it to make list looking like this [2;5;7;13] with using any starting parameter. When i delete 0 i get error message.
Another question how it's going to look like List.Fold i tried to write something similar but it can get only sum of this list ;( .
Here's how I would do this with a fold (with type annotations):
let orig = [2; 3; 2; 6]
let workingSum (origList:int list) : int list =
let foldFunc (listSoFar: int list) (item:int) : int list =
let nextValue =
match listSoFar with
| [] -> item
| head::_ -> head + item
nextValue::listSoFar
origList |> List.fold foldFunc [] |> List.rev
For help learning fold, here's how I would do this with a recursive function:
let workingSum' (origList: int list): int list =
let rec loop (listSoFar: int list) (origListRemaining:int list): int list =
match origListRemaining with
| [] -> listSoFar
| remainHead::remainTail ->
let nextValue =
match listSoFar with
| [] -> remainHead
| head::_ -> head + remainHead
loop (nextValue::listSoFar) remainTail
origList |> loop [] |> List.rev
Note that the signature of the inner loop function is really similar to the foldFunc of the previous example, with one major difference: instead of being passed in the next element, it's being passed in the remainder of the original list that hasn't been processed yet. I'm using a match expression to account for the two different possibilities of that remainder of the original list: either the list is empty (meaning we're done), or it's not (and we need to return a recursive call to the next step).