I am trying to insert a list into ETS to pull out later and for some reason it is saying it is a bad arg. I'm not sure if I'm inserting it incorrectly.
Is it just not possible to insert a list into ETS?
The offending line is ets:insert(table, [{parsed_file, UUIDs}]).
Here is the code:
readUUID(Id, Props) ->
fun () ->
%%TableBool = proplists:get_value(table_bool, Props, <<"">>),
[{_, Parsed}] = ets:lookup(table, parsed_bool),
case Parsed of
true ->
{uuids, UUIDs} = ets:lookup(table, parsed_bool),
Index = random:uniform(length(UUIDs)),
list_to_binary(lists:nth(Index, UUIDs));
false ->
[{_, Dir}] = ets:lookup(table, config_dir),
File = proplists:get_value(uuid_file, Props, <<"">>),
UUIDs = parse_file(filename:join([Dir, "config", File])),
ets:insert(table, [{parsed_file, {uuids, UUIDs}}]),
ets:insert(table, [{parsed_bool, true}]),
Index = random:uniform(length(UUIDs)),
list_to_binary(lists:nth(Index, UUIDs))
end
end.
parse_file(File) ->
{ok, Data} = file:read_file(File),
parse(Data, []).
parse([], Done) ->
lists:reverse(Done);
parse(Data, Done) ->
{Line, Rest} = case re:split(Data, "\n", [{return, list}, {parts, 2}]) of
[L,R] -> {L,R};
[L] -> {L,[]}
end,
parse(Rest, [Line|Done]).
If you create the table in the same proc with something like
ets:new(table, [set, named_table, public]).
then you should be ok. Default permissions are protected, where only creating process can write.
As a follow on to my comment about ets tables only containing tuples and what ets:lookup/2 returns the following line in your code:
{uuids, UUIDs} = ets:lookup(table, parsed_bool),
WILL ALWAYS GENERATE AN ERROR as ets:lookup/2 returns a list. The call 3 lines above may succeed. It seems like you are trying to do 2 lookups in table with key parsed_bool and expect to get 2 different types of answers: {_, Parsed} and {uuids, UUIDs}. Remember that ETS does not provide key-value tables but tables of tuples where one of the elements, default the first, is the key and doing ets:lookup/2 returns a list of the tuples with that key. How many you can get back depends on the properties of the table.
Check out the documentation of ETS tables.
Related
I want to sort my list descended but when I use the keyword .sort I get an error:
This is not a record, so it has no fields to access!
106| { model | teams = List.sort.map (\p -> {p | activated =
True}) model.teams, activatedOutput = True}
^^^^^^^^^ This sort value is a:
List comparable -> List comparable
But I need a record with a map field!
This is the line I have modified and with which I want to sort the list.
Submit ->
{ model | teams = List.sort.map (\p -> {p | activated = True}) model.teams, activatedOutput = True}
.sort is not a keyword, it is a function inside the List module. There are several types of sorting function.
The signature of sort is:
sort : List comparable -> List comparable
Which means that the values in the lists themselves have to be comparable which has special meaning in Elm. Specifically, only built-in things like numbers and strings are comparable. Custom types are not comparable, and neither are booleans.
It may sound strange to hear that booleans do not fit the comparable classification but consider this: What does it mean to ask the question, is True greater than or less than False in every scenario? Rather, you'll have to come up with your own definition of how to sort your custom object.
And for that, we can use the List.sortBy function, which has this signature:
sortBy : (a -> comparable) -> List a -> List a
This can sort a list of anything, as long as you provide a function that defines how to sort the thing.
So if you want those teams where activated is True to be shown at the top, you can use this for sorting:
List.sortBy (\x -> if x.activated then 0 else 1) model.teams
Whereas if you want teams where activated is False to be at the top, you can use this:
List.sortBy (\x -> if x.activated then 1 else 0) model.teams
I have:
type Person = String
type Book = String
type Database = [(Person,[Book])]
I'm trying to define a function:
books :: Database -> Person -> [Book]
that takes in
1) a list of tuples (which contain a string and a list of strings
2) a String name
and returns a list of strings (namely the books from the database)
I want to use list comprehension, but I don't know how to access elements within a list that is in the tuple inside of the database list.
Thoughts?
Example database would look like:
db = [("Bob", ["Red Riding Hood", "Alice in Wonderland"]), ("Carol", ["Game of Thrones"])]
And if I ask for say "Carol", it should return ["Game of Thrones"].
Since you have an association list you can use the lookup function. It pretty much works exactly like you want:
getVal :: Database -> String -> Maybe [String]
getVal = lookup
The only difference is that it returns a Maybe but IMHO that is the right behavior, consider what would happen if you didn't have a value in your database when you looked it up?
Since you want to use pattern matching here is the source of lookup
lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
lookup _key [] = Nothing
lookup key ((x,y):xys)
| key == x = Just y
| otherwise = lookup key xys
Or in your case
getVal :: Database -> String -> [String] --Avoids a Maybe if you want
getVal _key [] = []
getVal key ((x,y):xys)
| key == x = y
| otherwise = getVal key xys
As the other posters said, lookup is the way to go here: it's the standard procedure to search for something in an association list.
That said, a solution using a list comprehension would be
books :: Database -> Person -> [Book]
books db authorName = [book | (author, bookName) <- db,
author == authorName
book <- bookName]
It's taking out (author, bookName) tuples one by one, discarding the ones where the author doesn't match. If then adds the books of that author to the result.
Again, this implements a sort-of workaround for a function that's already in the standard libraries, and it's less readable in general. Really, use lookup.
I wouldn't use a list comprehension for implementing that function - list comprehensions are better suited for building lists.
What you are looking for is the Prelude function lookup:
lookup :: Eq a => a -> [(a, b)] -> Maybe b
As you can see it almost has the correct type, if a ~ Person and b ~ [Book] and after swapping the arguments. Since you want [Book] back and not Maybe [Book] you can wrap the whole thing inside fromMaybe, resulting in:
books db = fromMaybe [] . flip lookup db
How come the Hashtbl remove restores the previous binding.
Hashtbl.add t key1
Hashtbl.remove t key1
Hashtbl.remove t key1 => This should do anything but not restore the key1 !
Anyway, how come I can remove something making sure and if it was deleted before then proper flow shall be followed?
val remove : ('a, 'b) t -> 'a -> unit
Hashtbl.remove tbl x removes the current binding of x in tbl, restoring the previous binding if it exists. It does nothing if x is not bound in tbl.
There are two legitimate mode of uses of Hashtbl: always using Hashtbl.replace, which ensures that each key only has one binding in the table, or using the table as a multi-mapping (each key pointing to a list of values) with Hasthbl.add, Hashtbl.find and Hashtbl.find_all.
Please make sure that you understand which mode of use you're interested in. There is no point in adding several bindings to the same key if you don't want to keep old bindings (this can result in performance issues, memory leaks and stack overflows); in that case you should use Hashtbl.replace instead of Hashtbl.add, and Hashtbl.remove will do exactly what you expect.
If you are using the hashtable as a multi-mapping, and want a function that remove all bindings for a key, you can implement it yourslef (code untested):
let rec remove_all tbl key =
if Hashtbl.mem tbl key then begin
Hashtbl.remove tbl key;
remove_all tbl key
end
Edit: I just understood that another way to read your (hard to understand) question is "how can I make sure that there is a key to remove in the table, instead of silently doing nothing when remove is called?". cago provides a code snippet for that, in essence you can use Hashtbl.mem to check that the binding exists when you assume it should exist.
If you use Hashtbl.replace instead of Hashtbl.add you'll replace the current binding of the key in t. So the function Hashtbl.remove will not restore anything.
You can also write your own remove function :
let remove tbl key =
if Hashtbl.mem tbl key then Hashtbl.remove tbl key
else raise Nothing_to_remove_in_the_hashtbl
Hashtbl.replace t key1 value;;
remove t key1;;
remove t key1;; (* raise Nothing_to_remove_in_the_hashtbl *)
I want to append elements to a list and I'm not allowed to use the lists library or any other BIF. An example of how I want it to be:
Eshell V5.9.1 (abort with ˆ G)
1> Db = db:new().
[]
2> Db1 = db:write(apple, fruit, Db).
[{apple,fruit}]
3> Db2 = db:write(cucumber, vegetable, Db1).
[{apple,fruit},{cucumber,vegetable}]
The code I have now for this (not working):
write(Key, Element, []) -> [{Key, Element}|[]];
write(Key, Element, [H|T]) -> [H|write(Key,Element,T)].
The error I'm getting is when I do this:
3> Db2 = db:write(cucumber, vegetable, Db1).
** exception error: no match of right hand side value [{apple,fruit},{cucumber,vegetable}]
I understand the error message but I dont know how to go from here...
I suspect that this is just a case of Db2 already having a value, and it's a different value from the return value of db:write (which is [{apple,fruit},{cucumber,vegetable}] according to the error message). Type Db2. to see what value it has, and type f(Db2). to "forget" its value, so that you can assign to it again.
You can append element to the list by List ++ [Element]
Appending with ++ operator is not very recommended. You should use it only with small lists.
You have two options:
- lists:append (you said it's not an option ) or
- you can put in in front of a list with | operator.
I have a list of coordinates that I need to put on map. Is it possible in julius to iterate the list ? Right now I am creating an hidden table in hamlet and accessing that table in julius which does not seem to be an ideal solution.
Could some one point to a better solution ? Thanks.
edit: Passing a JSON string for the list (which can be read by julius) seems to solve my problem.
As far as I know, you can't directly iterate over a list in julius. However, you can use the Monoid instance for the Javascript type to accomplish a similar effect. For example:
import Text.Julius
import Data.Monoid
rows :: [Int] -> t -> Javascript
rows xs = mconcat $ map row xs
where
row x = [julius|v[#{show x}] = #{show x};
|]
Then you can use rows xs wherever you'd normally put a julius block. For example, in ghci:
> renderJavascript $ rows [1..5] ()
"v[1] = 1;\nv[2] = 2;\nv[3] = 3;\nv[4] = 4;\nv[5] = 5;\n"