How to recreate unzip - sml

I'm trying to recreate unzip and this is what I've gotten so far, before hitting into a roadblock.
fun myUnZip [] = []
| myUnZip ((x1,x2)::tail) = (* x1 :: myUnZip tail and also do x2 :: tail *)
Now, I know that second line is impossible, so that's why i put the comments there to show what I intend to do.
Any help on how I'm suppose to do this properly?
This is my second day at this language and I'm just trying to learn pattern matching. I'm currently reading the book Elementary Standard ML and it somewhat covers the topic of unzipping a tuple from a list. Although the book provided me with a solution, I was a bit overwhelmed by it and was hoping maybe someone else had a different solution towards it or could possibly provide some commentary on the book's unzipping solution.

fun unzip [] = ([], [])
| unzip ((x,y)::xys) =
let val (xs,ys) = unzip xys in (x::xs,y::ys) end;

Related

Struggling to extract a section of a list in Haskell

I am trying to implement a basic function but I'm out of practice with Haskell and struggling so would really appreciate some help. My question is specifically how to select a section of a list by index. I know how to in other languages but have been struggling
[ x | x <- graph, x!! > 5 && x!! <10 ]
I have been fiddling around with basic list comprehension similar to what is above, and while I know that isn't right I was hoping a similarly simple solution would be available.
If anyone wants more information or felt like helping on the further question I have included more information below, thanks!
type Node = Int
type Branch = [Node]
type Graph= [Node]
next :: Branch -> Graph -> [Branch]
This is the individual question for the "next" function
This is the general set up information but most importantly that the graph is represented as a flattened adjacency matric
Apologies for the two pictures but it seemed the best way to convey the information.
As pointed out in the comments !! does not give you the index of a value in the way it seems you expect. It is just an infix for getting an element of a list.
There is no way to get the index of x like this in Haskell since the x object doesn't keep track of where it is.
To fix this we can make a list of objects that do keep track of where they were. This can be achieved with zip.
zip [0..] graph
This creates a list of tuples each containing their index and the value in graph.
So you can write your list comprehensions as
[ x | (index, x) <- zip [0..] graph, index > 5, index < 10 ]
Now this is not going to be terribly fast since it still needs to go through every element of the list despite the fact that we know no element after the 11th will be used. For speed we would want to use a combination of take and drop.
drop 5 (take 10 graph)
However if we wanted to do some other selections (e.g. all even indexes), we can still go back to the list comprehension.
In this case, you could drop 5 <&> take 4. As in drop 5 x & take 4. Drop skips the first few elements and take leaves out all but the first few left after the drop.

How to add the elements of a list to a hashtable?

I'm trying to add elements to my hashtable by using a list.
I have a node type like the following :
type position = float * float
type node = position
I wrongfully assumed and started to write my function as if I could apply the same method of recursively building a normal list, but I don't know where to put my recursive call now.
This is what I've tried so far :
let init_dist nodes source =
let hshNodes = Hashtbl.create (List.length nodes) + 5 in
let rec init_dist_aux nodes hashtable source =
match nodes with
| [] -> hashtable
| x::tl > if x = source then Hashtbl.add hashtable (x,0.)
else Hashtbl.add hashtable (x,max_float)
The nodes argument is a list of node, source is a node.
I have no error output because I didn't run this due to the fact that it just couldn't work.
My goal is to be able to write a function that allows me to add bindings to my hashtbl using a list of node.
Thanks.
Your approach seems fine. I don't see any recursive call to init_dist_aux, so it will stop after adding the first element. Also it will generate a type error since one branch of your match returns a hash table and the other returns unit (()).
Adding the recursive call should fix both of these problems.
Update
You have this right now:
if x = source then
Hashtbl.add hashtable (x,0.)
else
Hashtbl.add hashtable (x,max_float)
What you want to have is this:
if x = source then
Hashtbl.add hashtable x 0.
else
Hashtbl.add hashtable x max_float;
init_dist_aux tl hashtable source
With this change, your init_dist_aux function already returns a hash table. There's nothing special to do to get this to happen.
But note that I don't see a call to init_dist_aux anywhere. You definitely need to call it to get things to work :-)
(As a side comment, if the code for init_dist_aux isn't fairly obvious to you you might need to spend a little more time thinking about recursion. Just a humble observation.)

concatenating a string onto all elements of [string] haskell

I'm new to haskell and can't seem to figure this out. I've been using the scalpel web scraping tool and want to concatenate a bunch of URL extensions with a URL.
For example, lets say we have scraped some URL extensions into a list of strings
result =["/contact","/content"]
and we have let
websiteURL = "www.website.com"
how do I arrive at the list ?
["www.website.com/contact", "www.website.com/content"]
map ("aaa"++) ["bbb", "ccc"]
==> [ "aaabbb", "aaaccc" ]
You want to traverse your list of extensions and apply a function to each, so some kind of map is required.
The function you want to apply is to append the websiteURL string, so the answer is:
map (mappend websiteURL) result
If you didn't know the mappend function, you could find it by searching hoogle for Monoid a => a -> a -> a.
(I'll let other people generalize to more abstract types if they want...)

Creating a list of players

I want to create a list of "players".
The user of the program can say how many players he wants.
Amount = io:get_line("how many players? \n"),
Int = string:to_integer(Amount),
List = Lists:seq(1,Int).
But now I want to create a list of players in the form [Player1, Player2...PlayerN].
Can someone tell me how to do so?
Remember that string:to_int/1 will return a tuple, not a single value. Also keep in mind that users do some pretty wild stuff in input, so you'll want to check that. (That said... when you're just trying to get a program written for yourself to test an idea, meh, whatever.)
{PlayerCount, _} = string:to_integer(io:get_line("How many players? ")),
Pretty simple. Mess around with this a bit. Input is its own world, and its good to think through this stuff a few times in toy programs (and give yourself insane input to see how the program reacts).
From here you can do a few things. If you just want a list of tuples that indicate you have a player whose serial number is a number, that's easy with a list comprehension:
Players = [{player, Number} || Number <- lists:seq(1, PlayerCount)],
You can write that as a map as well:
Players = lists:map(fun(N) -> {player, N} end, lists:seq(1, PlayerCount)),
I find the list comprehension more readable, though. Another alternative is to write your own custom recursive function. You almost never need to do this, but if you're new to programming it is good practice, and early on its way more readable because you see exactly what is happening each iteration:
player_list(Count) -> player_list(1, Count, []).
player_list(Max, Max, Players) ->
lists:reverse(Players);
player_list(Current, Max, Players) ->
player_list(Current + 1, Max, [make_new_player(Current) | Players]).
Note that the above is equivalent to, but more naturally stated than:
player_list(Current, Max, Players) ->
Next = Current + 1,
case Next == Max of
true -> lists:reverse(Players);
false -> player_list(Next, Max, [make_new_player(Current) | Players])
end.
Matching in function heads is much more clear and readable over the course of a program than a bunch of case and if statements. Over time, though, as I mentioned above, you will eventually stop writing recursive functions yourself (for the most part) and find yourself using a lot of list operations (map, fold, filter, list comprehensions, etc.) as you gain experience.
The details of make_new_player/0,1 are entirely up to you, of course -- you didn't indicate what sort of structure you wanted for their data, but you can do whatever you want there. Here are some other ways that might play out:
[make_new_player(Z) || Z <- lists:seq(1, PlayerCount)]
or
[#player{serial = Z} || Z <- lists:seq(1, PlayerCount)]

The most performant way to merge N lists, track duplicates, and sort them by date

I am new to Haskell and am wanting to know the most efficient way to merge an arbitrary number of lists of an arbitrary number of items. Here's example data:
LIST 1: steve
2014-01-20 | cookies | steve
LIST 2: chris
2014-02-05 | cookies | chris
LIST 3: mark
2014-09-30 | brownies | mark
2014-03-30 | candy | mark
2014-05-12 | pie | mark
LIST 4: anthony
2014-05-18 | cookies | anthony
2013-12-25 | fudge | anthony
LIST 5: andy
2014-10-04 | cookies | andy
LIST 7: john
2014-06-19 | pie | john
RESULTING LIST
2014-10-04 | cookies | andy chris steve anthony
2014-09-30 | brownies | mark
2014-06-19 | pie | john mark
2014-03-30 | candy | mark
2013-12-25 | fudge | anthony
Notice the lists are all oriented around people and may or may not be sorted by date, and the result needs to merge the prior lists, group and create a list where the dessert is unique but has a list of the constituent people who ate it, sorted by date reverse chronologically.
What is the most performant way to solve a problem, is in most cases not answerable neither in haskell nor in any other programming language I think.
A better approach would be to think about, how can I solve this problem (at all) and keep a few principles in the back of your mind.
testability
abstraction and expressiveness
maintainability
readability
performance
Maybe I've forgot about something but for your problem I want to give a hintlist
If I know all the items and names in advance I would use algebraic datatypes to model this situation
data Name = Mark | Chris ...
deriving (Ord,Eq,Show)
data Items = Pie | Cookies ...
deriving (Ord,Eq,Show)
If I do not already know how haskell represents a date datatype I can use a plain old String to model this, or I would use hoogle to see if there already exists a date-thingy.
> hoogle date
...
Data.Time.Calendar...
...
So I guess the Data.Time.Calendar module seems a good choice for that, and I would look at its documentation which can both be found online or if you install the package locally you can use haddock to generate it yourself from the source files.
Next step I would approach is to model the "database" of course there exists libraries to work with sqly stuff or acid-state a database that uses algebraic datatypes instead of a database backend. But for getting a better grasp of haskell I would try to reinvent the wheel for once and use either a list of tupels, or a dictionary-like collection, which is in haskell called Map. But working with Map one has to be careful and do a qualified import as most of its provided functions would lead to a name collision with the functions in the standard library (Prelude).
import qualified Map as M
and to model my database I would use the Items as keys and a tuple of date and list of names as the values and as I want to be aware that this is my database I would provide a type alias for that.
type DB = M.Map Item (Date, [Name])
For working with that I would again have a glance at the Map docu and be happy to find the functions insertWith, empty and toList. And for the insertWith functions I would think of a mixture of max and list cons (:) functions to make new entries.
To get a better feel for the whole thing I would fire up ghci and import qualified Data.Map as M and fool around with some examples using M.Map String (String,[Int]) or whatnot to model my data in a first approximation.
For the result I have to sort the toList of my Map by date, which is just a little problem. The type of my toList myDb is [(Item,(Date,[Name]))] so sorting by the fst.snd with sortBy should lead to the desired result.
After I'd done this much, I'd take a break and read something about parsers - to get all my files in context with my program. A search with the search engine of your least distrust will turn up a few articles worth reading (Parser Parsec Haskell).
If all of this is too complicated I would go back and change all my types to be Strings and hope I wouldn't have any typeos until I had time to read again about parsers ;-).
For any problems in the intermediate steps people here will be glad to help you, assumed you provide a concrete question/problem description.
If all of this were not performant enough, the profiling tools provided by haskell are good enough to help me, but this is my last concern to solve.