I'm tasked with creating a list of m word portmanteaus with n letter overlap from a given list of words.
For example, a 2 word 2 letter overlap portmanteau would be: "collegenetics" made from "college" and "genetics". A 3 word 2 letter overlap could be "firegaluminum" made of "fire", "regal" and "aluminum".
I have written a function singleport with this syntax:
let singleport word1 word2 n =
match suffix word1 n = prefix word2 n with
| false -> "No Port"
| true -> word1 ^ (prefixless word2 n)
which identifies whether or not two words could be portmanteaus. However, I'm struggling to identify a way to run this recursively in order to compare two elements of a list, all while constructing a new list that records all the possible portmantaus.
I figured List.fold_left could be used because of the use of the accumulator, but I don't know how to implement it and I would greatly appreciate any advice. Thank you very much!
One of the approaches to attack this task is to split it into small understandable subtasks, and then try to merge them. This is the deductive approach.
Deductively
Applying the deductive method to your task, we can split it in the following way:
create a list of consecutive pairs
map the list for portmanteaus
join the result
To create a list of pairs, you need to write the following function:
(** [pair_list xs] given the list [xs], produces a list of consecutive pairs.
Fails with an invalid argument, if the list has odd length. *)
val pair_list : 'a list -> ('a * 'a) list
With such a function, you can use map to transform each pair to a list of portmanteau, mapping a pair to an empty list, if it is impossible. E.g., given this function:
val portmanteau : (string * string) -> string list
And now we can join everything with List.concat:
let portmanteau_of_list xs =
List.map portmanteau (pair_list xs) |> List.concat
Inductively
Another approach is to move from the opposite direction, i.e., not from top to down, but from the bottom. So inductive reasoning about this task would be the following:
portmanteaus of an empty list is an empty list,
portmanteaus of the list of one element is an error
portmanteaus of a list that is greater than two when the first two elements don't form a portmanteau is the portmanteaus of the rest elements of the list
portmanteaus of a list greater than two when the first two elements form a portmanteau is the portmanteaus of these two elements plus portmanteaus of the rest elements of the list.
The same in OCaml (untested):
let rec portmanteau_of_list = function
| [] -> []
| [_] -> failwith "odd list"
| x :: y :: xs -> match portmanteau x y with
| None -> portmanteau_of_list xs
| Some p -> p :: portmanteau_of_list xs
Related
I have two lists -- one is a grid list of tuples and the other one is a list of coordinates -- to be compared, such that the list of coordinates is always a sublist of the grid list. Now I want to check each tuple in the grid list whether it's in the coordinates list or not. If there exists one, substitute the tuple in the grid list with a "#" and if not, substitute with a "_".
Below is my best attempt and it never works.
getHash :: [(Int,Int)] -> [(Int,Int)] -> [String]
getHash [(x1,y1)] [(x2,y2)] | (x1,y1) `elem` [(x2,y2)] : (x1,y1) = "#"
| otherwise (x1,y1) = "_"
where (x1,y1) <- [(x1,y1)]
You want to replace each element in a list with "#" or "_" depending on whether that element is an element of a second list. We can split that into two parts. The first part, "Replace each element in a list with the result of calling a function with that element as its argument" is map. The second, doing something based on whether an item is an element of a list, does indeed use elem. So we will
map over a list and
call elem on each element,
comparing it with the list of known coordinates, and
decide which string to replace the element of the list with based on the result of the call to elem.
getHash known xs = map (\x -> if x `elem` known then "#" else "_") xs
Now, why did I give the known list first? It's mostly personal preference, but I think it works a bit better with partial application. getHash [(1,2)] is a function that compares a list given as an argument with a static 'known' list. And since xs is the right position for it, we can also use eta reduction in the definition:
getHash known = map (\x -> if x `elem` known then "#" else "_")
Running insert ls n should return a list of piles from taking ls and inserting n so that either n has been added to the head of the first pile in ls whose previous head is greater than or equal to n, or if it doesn't exist, a new pile containing just n is added to the end of ls.
For example,
insert [[4]; [5]] 3 = [[3;4]; [5]]
insert [[2]; [6]] 4 = [[2]; [4;6]]
insert [[3]] 4 = [[3]; [4]]
Basically, I'm trying to use the sort helper function that appends to the list if the element is less than the first in the list, and then in that case to just return the rest of the list.
let rec insert ls n =
match n with
| [] -> [x]
| y::ys -> if x < y then x::y::ys else y::insert x ys;;
let rec sort n =
match n with
| [] -> []
| x::xs -> insert x (sort xs);;
You keep confusing the order and type of arguments in your insert function. In your text description and following from the examples section, insert has type 'a list list -> 'a -> 'a list list, but when you try to write your insert function, you match the element n with a list. In the same manner, when you call insert from sort you pass the element as the first argument.
Next, your insert function shall return a list of lists, but in the first branch of your match, [] -> [x], you return just a list. In addition, there is no x variable bound in this match or anywhere else, probably you meant n?
Finally, when you compare the first element of the input list with the element n you compare the whole pile, instead of the head of the pile.
So let's try to rectify these problems, first of all, we have to match on ls instead of n,
let rec insert ls n =
match ls with
(* ^^
ls not n! *)
Next, if we have an empty input, then we need to return a list containing a single pile, where a pile is a list itself,
| [] -> [[n]] (* a list containing a list with a single element `n` *)
Finally, when we match on the head of the input list, we have to keep in mind that the head is the list itself, i.e., a pile, so we need to unpack it as well,
| (x::xs)::ys ->
(* ^^^^^^^
here x is the head of the pile, and x::xs is the whole pile *)
and pack it back,
if n < x then (n::x::xs)::ys else (x::xs)::insert ys n
(* ^^^^^^^^^^ ^^^^^^^
extended pile intact pile *)
The next step would be to make the match complete, i.e., to think what to do when the pile is empty itself (could it be?) and what to do when x is equal to n.
I'm beginner in haskell and I tried to add a number in a 2D list with specific index in haskell but I don't know how to do
example i have this:
[[],[],[]]
and I would like to put a number (3) in the index 1 like this
[[],[3],[]]
I tried this
[array !! 1] ++ [[3]]
but it doesn't work
As you may have noticed in your foray so far, Haskell isn't like many other languages in that it is generally immutable, so trying to change a value, especially in a deeply nested structure like that, isn't the easiest thing. [array !! 1] would give you a nested list [[]] but this is not mutable, so any manipulations you do this structure won't be reflected in the original array, it'll be a separate copy.
(There are specialized environments where you can do local mutability, as with e.g. Vectors in the ST monad, but these are an exception.)
For what you're trying to do, you'll have to deconstruct the list to get it to a point where you can easily make the modification, then reconstruct the final structure from the (modified) parts.
The splitAt function looks like it will help you with this: it takes a list and separates it into two parts at the index you give it.
let array = [[],[],[]]
splitAt 1 array
will give you
([[]], [[],[]])
This helps you by getting you closer to the list you want, the middle nested list.
Let's do a destructuring bind to be able to reconstruct your final list later:
let array = [[],[],[]]
(beginning, end) = splitAt 1 array
Next, you'll need to get at the sub-list you want, which is the first item in the end list:
desired = head end
Now you can make your modification -- note, this will produce a new list, it won't modify the one that's there:
desired' = 3:desired
Now we need to put this back into the end list. Unfortunately, the end list is still the original value of [[],[]], so we'll have to replace the head of this with our desired' to make it right:
end' = desired' : (tail end)
This drops the empty sub-list at the beginning and affixes the modified list in its place.
Now all that's left is to recombine the modified end' with the original beginning:
in beginning ++ end'
making the whole snippet:
let array = [[],[],[]]
(beginning, end) = splitAt 1 array
desired = head end
desired' = 3:desired
end' = desired' : (tail end)
in beginning ++ end'
or, if you're entering all these as commands in the REPL:
let array = [[],[],[]]
let (beginning, end) = splitAt 1 array
let desired = head end
let desired' = 3:desired
let end' = desired' : (tail end)
beginning ++ end'
As paul mentions, things in Haskell are immutable. What you want to do must be done not be modifying the list in place, but by destructuring the list, transforming one of its parts, and restructuring the list with this changed part. One way of destructuring (via splitAt) is put forth there; I'd like to offer another.
Lists in Haskell are defined as follows:
data [] a = [] | a : [a]
This reads "A list of a is either empty or an a followed by a list of a". (:) is pronounced "cons" for "constructor", and with it, you can create nonempty lists.
1 : [] -> [1]
1 : [2,3] -> [1,2,3]
1 : 2 : 3 : [] -> [1,2,3]
This goes both ways, thanks to pattern matching. If you have a list [1,2,3], matching it to x : xs will bind its head 1 to the name x and its tail [2,3] to xs. As you can see, we've destructured the list into the two pieces that were initially used to create it. We can then operate on those pieces before putting the list back together:
λ> let x : xs = [1,2,3]
λ> let y = x - 5
λ> y : xs
[-4,2,3]
So in your case, we can match the initial list to x : y : z : [], compute w = y ++ [3], and construct our new list:
λ> let x : y : z : [] = [[],[],[]]
λ> let w = y ++ [3]
λ> [x,w,z]
[[],[3],[]]
But that's not very extensible, and it doesn't solve the problem you pose ("with specific index"). What if later on we want to change the thousandth item of a list? I'm not too keen on matching that many pieces. Fortunately, we know a little something about lists—index n in list xs is index n+1 in list x:xs. So we can recurse, moving one step along the list and decrementing our index each step of the way:
foo :: Int -> [[Int]] -> [[Int]]
foo 0 (x:xs) = TODO -- Index 0 is x. We have arrived; here, we concatenate with [3] before restructuring the list.
foo n (x:xs) = x : foo (n-1) xs
foo n [] = TODO -- Up to you how you would like to handle invalid indices. Consider the function error.
Implement the first of those three yourself, assuming you're operating on index zero. Make sure you understand the recursive call in the second. Then read on.
Now, this works. It's not all that useful, though—it performs a predetermined computation on a specified item in a list of one particular type. It's time to generalize. What we want is a function of the following type signature:
bar :: (a -> a) -> Int -> [a] -> [a]
where bar f n xs applies the transformation f to the value at index n in the list xs. With this, we can implement the function from before:
foo n xs = bar (++[3]) n xs
foo = bar (++[3]) -- Alternatively, with partial application
And believe it or not, changing the foo you already wrote into the much more useful bar is a very simple task. Give it a try!
I have two strings
a :: [String]
a = ["A1","A2","B3","C3"]
and
b :: [String]
b = ["A1","B2","B3","D5"]
And I want to calculate the difference between two strings based on the first character and second character and combination of two characters.
If the combination of two elements are the same, it would be calculate as 1
The function I declared is
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys) = (a,b)
where
a = 0 in
???
b = ????
I know that I should have a increment variable to count the correct element, and where I should put it in? For now I totally have no idea about how to do that, can anyone give me some hint??
The desired result would be
(2,["B2","D5"])
How should I do that?
I assume that the lists have the same size.
The differences between the two lists
Let's focus on the main part of the problem:
Prelude> a=["A1","A2","B3","C3"]
Prelude> b=["A1","B2","B3","D5"]
First, notice that the zip method zips two lists. If you use it on a and b, you get:
Prelude> zip a b
[("A1","A1"),("A2","B2"),("B3","B3"),("C3","D5")]
Ok. It's now time to compare the terms one to one. There are many ways to do it.
Filter
Prelude> filter(\(x,y)->x/=y)(zip a b)
[("A2","B2"),("C3","D5")]
The lambda function returns True if the elements of the pair are different (/= operator). Thus, the filter keeps only the pairs that don't match.
It's ok, but you have to do a little more job to keep only the second element of each pair.
Prelude> map(snd)(filter(\(x,y)->x/=y)(zip a b))
["B2","D5"]
map(snd) applies snd, which keeps only the second element of a pair, to every discordant pair.
Fold
A fold is more generic, and may be used to implement a filter. Let's see how:
Prelude> foldl(\l(x,y)->if x==y then l else l++[y])[](zip a b)
["B2","D5"]
The lambda function takes every pair (x,y) and compares the two elements. If they have the same value, the accumulator list remains the identical, but if the values are different, the accumulator list is augmented by the second element.
List comprehension
This is more compact, and should seem obvious to every Python programmer:
Prelude> [y|(x,y)<-zip a b, x/=y] -- in Python [y for (x,y) in zip(a,b) if x!= y]
["B2","D5"]
The number of elements
You want a pair with the number of elements and the elements themselves.
Fold
With a fold, it's easy but cumbersome: you will use a slightly more complicated accumulator, that stores simultaneously the differences (l) and the number of those differences (n).
Prelude> foldl(\(n,l)(x,y)->if x==y then (n,l) else (n+1,l++[y]))(0,[])$zip a b
(2,["B2","D5"])
Lambda
But you can use the fact that your output is redundant: you want a list preceeded by the length of that list. Why not apply a lambda that does the job?
Prelude> (\x->(length x,x))[1,2,3]
(3,[1,2,3])
With a list comprehension, it gives:
Prelude> (\x->(length x,x))[y|(x,y)<-zip a b, x/=y]
(2,["B2","D5"])
Bind operator
Finally, and for the fun, you don't need to build the lambda this way. You could do:
Prelude> ((,)=<<length)[y|(x,y)<-zip a b,x/=y]
(2,["B2","D5"])
What happens here? (,) is a operator that makes a pair from two elements:
Prelude> (,) 1 2
(1,2)
and ((,)=<<length) : 1. takes a list (technically a Foldable) and passes it to the length function; 2. the list and the length are then passed by =<< (the "bind" operator) to the (,) operator, hence the expected result.
Partial conclusion
"There is more than than one way to do it" (but it's not Perl!)
Haskell offers a lot of builtins functions and operators to handle this kind of basic manipulation.
What about doing it recursively? If two elements are the same, the first element of the resulting tuple is incremented; otherwise, the second element of the resulting tuple is appended by the mismatched element:
calcP :: [String] -> [String] -> (Int,[String])
calcP (x:xs) (y:ys)
| x == y = increment (calcP xs ys)
| otherwise = append y (calcP xs ys)
where
increment (count, results) = (count + 1, results)
append y (count, results) = (count, y:results)
calcP [] x = (0, x)
calcP x [] = (0, [])
a = ["A1","A2","B3","C3"]
b = ["A1","B2","B3","D5"]
main = print $ calcP a b
The printed result is (2,["B2","D5"])
Note, that
calcP [] x = (0, x)
calcP x [] = (0, [])
are needed to provide exhaustiveness for the pattern matching. In other words, you need to provide the case when one of the passed elements is an empty list. This also provides the following logic:
If the first list is greater than the second one on n elements, these n last elements are ignored.
If the second list is greater than the first one on n elements, these n last elements are appended to the second element of the resulting tuple.
I'd like to propose a very different method than the other folks: namely, compute a "summary statistic" for each pairing of elements between the two lists, and then combine the summaries into your desired result.
First some imports.
import Data.Monoid
import Data.Foldable
For us, the summary statistic is how many matches there are, together with the list of mismatches from the second argument:
type Statistic = (Sum Int, [String])
I've used Sum Int instead of Int to specify how statistics should be combined. (Other options here include Product Int, which would multiply together the values instead of adding them.) We can compute the summary of a single pairing quite simply:
summary :: String -> String -> Statistic
summary a b | a == b = (1, [ ])
| otherwise = (0, [b])
Combining the summaries for all the elements is just a fold:
calcP :: [String] -> [String] -> Statistic
calcP as bs = fold (zipWith summary as bs)
In ghci:
> calcP ["A1", "A2", "B3", "C3"] ["A1", "B2", "B3", "D5"]
(Sum {getSum = 2},["B2","D5"])
This general pattern (of processing elements one at a time into a Monoidal type) is frequently useful, and spotting where it's applicable can greatly simplify your code.
I have been working with Haskell for a little over a week now so I am practicing some functions that might be useful for something. I want to compare two lists recursively. When the first list appears in the second list, I simply want to return the index at where the list starts to match. The index would begin at 0. Here is an example of what I want to execute for clarification:
subList [1,2,3] [4,4,1,2,3,5,6]
the result should be 2
I have attempted to code it:
subList :: [a] -> [a] -> a
subList [] = []
subList (x:xs) = x + 1 (subList xs)
subList xs = [ y:zs | (y,ys) <- select xs, zs <- subList ys]
where select [] = []
select (x:xs) = x
I am receiving an "error on input" and I cannot figure out why my syntax is not working. Any suggestions?
Let's first look at the function signature. You want to take in two lists whose contents can be compared for equality and return an index like so
subList :: Eq a => [a] -> [a] -> Int
So now we go through pattern matching on the arguments. First off, when the second list is empty then there is nothing we can do, so we'll return -1 as an error condition
subList _ [] = -1
Then we look at the recursive step
subList as xxs#(x:xs)
| all (uncurry (==)) $ zip as xxs = 0
| otherwise = 1 + subList as xs
You should be familiar with the guard syntax I've used, although you may not be familiar with the # syntax. Essentially it means that xxs is just a sub-in for if we had used (x:xs).
You may not be familiar with all, uncurry, and possibly zip so let me elaborate on those more. zip has the function signature zip :: [a] -> [b] -> [(a,b)], so it takes two lists and pairs up their elements (and if one list is longer than the other, it just chops off the excess). uncurry is weird so lets just look at (uncurry (==)), its signature is (uncurry (==)) :: Eq a => (a, a) -> Bool, it essentially checks if both the first and second element in the pair are equal. Finally, all will walk over the list and see if the first and second of each pair is equal and return true if that is the case.