Haskell HDBC.Sqlite3 fetchAllRows - sqlite

Since I am an absolute Haskell beginner, but determined to conquer it, I am asking for help again.
using:
fetchData2 = do
conn <- connectSqlite3 "dBase.db"
statement <- prepare conn "SELECT * FROM test WHERE id > 0"
execute statement []
results <- fetchAllRows statement
print results
returns:
[[SqlInt64 3,SqlByteString "Newco"],[SqlInt64 4,SqlByteString "Oldco"],[SqlInt64 5,SqlByteString "Mycom"],[SqlInt64 4,SqlByteString "Oldco"],[SqlInt64 5,SqlByteString "Mycom"]]
Is there a clever way to clean this data into Int and [Char], in other words omitting types SqlInt64 and SqlByteString.

You could define a helper:
fetchRowFromSql :: Convertible SqlValue a => Statement -> IO (Maybe [a])
fetchRowFromSql = fmap (fmap (fmap fromSql)) . fetchRow
The implementation looks a bit daunting, but this is just because we need to drill down under the layered functors as you already noted (first IO, then Maybe and lastly []). This returns something that is convertible from a SqlValue. There are a bunch of these defined already. See e.g. the docs. An example (using -XTypeApplications):
fetchRowFromSql #String :: Statement -> IO (Maybe [String])
I should perhaps add that the documentation mentions that fromSql is unsafe. Meaning that if you try to convert a sql value to an incompatible Haskell value the program will halt.

Related

currying multiple functions in parallel in F#

I'm trying to learn F# at the moment and have come up on a problem I can't solve and can't find any answers for on google.
Initially I wanted a log function that would work like the printf family of functions whereby I could provide a format string and a number of arguments (statically checked) but which would add a little metadata before printing it out. With googling, I found this was possible using a function like the following:
let LogToConsole level (format:Printf.TextWriterFormat<'T>) =
let extendedFormat = (Printf.TextWriterFormat<string->string->'T> ("%s %s: " + format.Value))
let date = DateTime.UtcNow.ToString "yyyy-MM-dd HH:mm:ss.fff"
let lvl = string level
printfn extendedFormat date lvl
having the printfn function as the last line of this function allows the varargs-like magic of the printf syntax whereby the partially-applied printfn method is returned to allow the caller to finish applying arguments.
However, if I have multiple such functions with the same signature, say LogToConsole, LogToFile and others, how could I write a function that would call them all keeping this partial-application magic?
Essential I'm looking for how I could implement a function MultiLog
that would allow me to call multiple printf-like functions from a single function call Such as in the ResultIWant function below:
type LogFunction<'T> = LogLevel -> Printf.TextWriterFormat<'T> -> 'T
let MultiLog<'T> (loggers:LogFunction<'T>[]) level (format:Printf.TextWriterFormat<'T>) :'T =
loggers
|> Seq.map (fun f -> f level format)
|> ?????????
let TheResultIWant =
let MyLog = MultiLog [LogToConsole; LogToFile]
MyLog INFO "Text written to %i outputs" 2
Perhaps the essence of this question can be caught more succintly: given a list of functions of the same signature how can I partially apply them all with the same arguments?
type ThreeArg = string -> int -> bool -> unit
let funcs: ThreeArg seq = [func1; func2; func3]
let MagicFunction = ?????
// I'd like this to be valid
let partiallyApplied = MagicFunction funcs "string"
// I'd also like this to be valid
let partiallyApplied = MagicFunction funcs "string" 255
// and this (fullyApplied will be `unit`)
let fullyApplied = MagicFunction funcs "string" 255 true
To answer the specific part of the question regarding string formatting, there is a useful function Printf.kprintf which lets you do what you need in a very simple way - the first parameter of the function is a continuation that gets called with the formatted string as an argument. In this continuation, you can just take the formatted string and write it to all the loggers you want. Here is a basic example:
let Loggers = [printfn "%s"]
let LogEverywhere level format =
Printf.kprintf (fun s ->
let date = DateTime.UtcNow.ToString "yyyy-MM-dd HH:mm:ss.fff"
let lvl = string level
for logger in Loggers do logger (sprintf "%s %s %s" date lvl s)) format
LogEverywhere "BAD" "hi %d" 42
I don't think there is a nice and simple way to do what you wanted to do in the more general case - I suspect you might be able to use some reflection or static member constraints magic, but fortunately, you don't need to in this case!
There is almost nothing to add to a perfect #TomasPetricek answer as he is basically a "semi-god" in F#. Another alternative, which comes to mind, is to use a computation expression (see, for example: https://fsharpforfunandprofit.com/series/computation-expressions.html). When used properly it does look like magic :) However, I have a feeling that it is a little bit too heavy for the problem, which you described.

Erlang: How to create a function that returns a string containing the date in YYMMDD format?

I am trying to learn Erlang and I am working on the practice problems Erlang has on the site. One of them is:
Write the function time:swedish_date() which returns a string containing the date in swedish YYMMDD format:
time:swedish_date()
"080901"
My function:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
string:substr((integer_to_list(YYYY, 3,4)++pad_string(integer_to_list(MM))++pad_string(integer_to_list(DD)).
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
I'm getting the following errors when compiled.
demo.erl:6: syntax error before: '.'
demo.erl:2: function swedish_date/0 undefined
demo.erl:9: Warning: function pad_string/1 is unused
error
How do I fix this?
After fixing your compilation errors, you're still facing runtime errors. Since you're trying to learn Erlang, it's instructive to look at your approach and see if it can be improved, and fix those runtime errors along the way.
First let's look at swedish_date/0:
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
Why convert the list to a tuple? Since you use the list elements individually and never use the list as a whole, the conversion serves no purpose. You can instead just pattern-match the returned tuple:
{YYYY,MM,DD} = date(),
Next, you're calling string:substr/1, which doesn't exist:
string:substr((integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD))).
The string:substr/2,3 functions both take a starting position, and the 3-arity version also takes a length. You don't need either, and can avoid string:substr entirely and instead just return the assembled string:
integer_to_list(YYYY,3,4) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
Whoops, this is still not right: there is no such function integer_to_list/3, so just replace that first call with integer_to_list/1:
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
Next, let's look at pad_string/1:
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
There's a runtime error here because '0' is an atom and you're attempting to append String, which is a list, to it. The error looks like this:
** exception error: bad argument
in operator ++/2
called as '0' ++ "8"
Instead of just fixing that directly, let's consider what pad_string/1 does: it adds a leading 0 character if the string is a single digit. Instead of using if to check for this condition — if isn't used that often in Erlang code — use pattern matching:
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
The first clause matches a single-element list, and returns a new list with the element D preceded with $0, which is the character constant for the character 0. The second clause matches all other arguments and just returns whatever is passed in.
Here's the full version with all changes:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
{YYYY,MM,DD} = date(),
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD)).
pad_string([D]) ->
[$0,D];
pad_string(S) ->
S.
But a simpler approach would be to use the io_lib:format/2 function to just format the desired string directly:
swedish_date() ->
io_lib:format("~w~2..0w~2..0w", tuple_to_list(date())).
First, note that we're back to calling tuple_to_list(date()). This is because the second argument for io_lib:format/2 must be a list. Its first argument is a format string, which in our case says to expect three arguments, formatting each as an Erlang term, and formatting the 2nd and 3rd arguments with a width of 2 and 0-padded.
But there's still one more step to address, because if we run the io_lib:format/2 version we get:
1> demo:swedish_date().
["2015",["0",56],"29"]
Whoa, what's that? It's simply a deep list, where each element of the list is itself a list. To get the format we want, we can flatten that list:
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
Executing this version gives us what we want:
2> demo:swedish_date().
"20150829"
Find the final full version of the code below.
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
lists:flatten(io_lib:format("~w~2..0w~2..0w", tuple_to_list(date()))).
UPDATE: #Pascal comments that the year should be printed as 2 digits rather than 4. We can achieve this by passing the date list through a list comprehension:
swedish_date() ->
DateVals = [D rem 100 || D <- tuple_to_list(date())],
lists:flatten(io_lib:format("~w~2..0w~2..0w", DateVals)).
This applies the rem remainder operator to each of the list elements returned by tuple_to_list(date()). The operation is needless for month and day but I think it's cleaner than extracting the year and processing it individually. The result:
3> demo:swedish_date().
"150829"
There are a few issues here:
You are missing a parenthesis at the end of line 6.
You are trying to call integer_to_list/3 when Erlang only defines integer_to_list/1,2.
This will work:
-module(demo).
-export([swedish_date/0]).
swedish_date() ->
[YYYY,MM,DD] = tuple_to_list(date()),
string:substr(
integer_to_list(YYYY) ++
pad_string(integer_to_list(MM)) ++
pad_string(integer_to_list(DD))
).
pad_string(String) ->
if
length(String) == 1 -> '0' ++ String;
true -> String
end.
In addition to the parenthesis error on line 6, you also have an error on line 10 where yo use the form '0' instead of "0", so you define an atom rather than a string.
I understand you are doing this for educational purpose, but I encourage you to dig into erlang libraries, it is something you will have to do. For a common problem like this, it already exists function that help you:
swedish_date() ->
{YYYY,MM,DD} = date(), % not useful to transform into list
lists:flatten(io_lib:format("~2.10.0B~2.10.0B~2.10.0B",[YYYY rem 100,MM,DD])).
% ~X.Y.ZB means: uses format integer in base Y, print X characters, uses Z for padding

Pulling out a column in all records in a Sqlite table into a concatenated string in Haskell with Persist

I'm trying to learn Haskell, specifically Snap, Blaze HTML5 and Persist. I would like to take every row in a table, select a single column from it, and then concatenate the values into a single string.
I've previously worked with C#'s LINQ quite extensively and under Entity Framework I could do it like this:
String.Join(", ", dbContext.People.Select(p => p.Name));
This would compile down to SELECT Name FROM People, with C# then concatenating those rows into a string with ", " in between.
To try and get the concatenation part right, I put this together, which seems to work:
intercalate ", " $ map show [1..10]
(it counts 1-9, concatenates with ", " in between the items)
However, I can't get this to work with Database.Persist.Sqlite. I'm not sure I quite understand the syntax here in Haskell. To contact the DB and retrieve the rows, I have to call: (as far as I understand)
runSqlite "TestDB" $ selectList ([] :: [Filter Person]) [] 0 0
The problem is that I'm not sure how to get the list out of runSqlite. runSqlite doesn't return the type I'm after, so I can't use the return value of runSqlite. How would I do this?
Thank you for reading.
To clarify:
Snap requires that I define a function to return the HTML I wish to send back to the client making the HTTP request. This means that:
page = runSqlite "TestDB" $ do
{pull data from the DB)
Is no-go as I can't return the data via the runSqlite call, and as far as I know I can't have a variable in the page function which is set within the runSqlite do block. All examples I can find just write to IO in the runSqlite do block, which is not what needs to be done here.
The type of runSqlite is:
runSqlite :: (MonadBaseControl IO m, MonadIO m) => Text -> SqlPersistT (NoLoggingT (ResourceT m)) a -> m a
And the type of selectList is:
[Filter val] -> [SelectOpt val] -> m [Entity val]
So, you can actually, use the nice do notation of Monad, to extract it:
runSqlite "TestDB" $ do
myData <- selectList ([] :: [Filter Person]) [] 0 0
-- Now do stuff with myData
The <- thing gets the list out of the monad. I would suggest you to go through this chapter to get an idea of how Persistent is used. Note that the chapters in the book assume a basic Haskell understanding.
The issue is that I want to use the selectList outside of runSqlite as
I need to pass the concatenated string to a Blaze HTML5 tag builder:
body $ do p (concatenated list...)
For this case, just define a function that does your intended task:
myLogic :: [SqlColumnData] -> String -- Note that SqlColumnData is hypothetical
myLogic xs = undefined
And then just call them appropriately in your main function:
main = runSqlite "TestDB" $ do
myData <- selectList ([] :: [Filter Person]) [] 0 0
let string = myLogic myData
-- do any other remaining stuff
It hadn't clicked that if I didn't use a do block with runSqlite, the result of the last call in the statement was the return value of the statement - this makes total sense.
https://gist.github.com/egonSchiele/5400694
In this example (not mine) the readPosts function does exactly what I'm after and cleared up some Haskell syntax confusion.
Thank you for your help #Sibi.

Erlang syntax for nested function with if

I've been looking around and can't find examples of this and all of my syntax wrestling skills are failing me. Can someone please tell me how to make this compile?? My ,s ;s or .s are just wrong I guess for defining a nested function...
I'm aware there is a function for doing string replaces already so I don't need to implement this, but I'm playing with Erlang trying to pick it up so I'm hand spinning some of the basics I need to use..
replace(Whole,Old,New) ->
OldLen = length(Old),
ReplaceInit = fun(Next, NewWhole) ->
if
lists:prefix(Old, [Next|NewWhole]) -> {_,Rest} = lists:split(OldLen-1, NewWhole), New ++ Rest;
true -> [Next|NewWhole]
end,
lists:foldr(ReplaceInit, [], Whole).
Basically I'm trying to write this haskell (also probably bad but beyond the point):
repl xs ys zs =
foldr replaceInit [] xs
where
ylen = length ys
replaceInit y newxs
| take ylen (y:newxs) == ys = zs ++ drop (ylen-1) newxs
| otherwise = y:newxs
The main problem is that in an if you are only allowed to use guards as tests. Guards are very restricted and, amongst other things, calls to general Erlang functions are not allowed. Irrespective of whether they are part of the OTP release or written by you. The best solution for your function is to use case instead of if. For example:
replace(Whole,Old,New) ->
OldLen = length(Old),
ReplaceInit = fun (Next, NewWhole) ->
case lists:prefix(Old, [Next|NewWhole]) of
true ->
{_,Rest} = lists:split(OldLen-1, NewWhole),
New ++ Rest;
false -> [Next|NewWhole]
end
end,
lists:foldr(ReplaceInit, [], Whole).
Because of this if is not used that often in Erlang. See about if and about guards in the Erlang documentation.

Collecting the output of an external command using OCaml

What is the right way to call an external command and collect its output in OCaml?
In Python, I can do something like this:
os.popen('cmd').read()
How I can get all of an external program's output in OCaml? Or, better, OCaml with Lwt?
Thanks.
You want Unix.open_process_in, which is described on page 388 of the OCaml system manual, version 3.10.
For Lwt,
val pread : ?env:string array -> command -> string Lwt.t
seems to be a good contender. Documentation here: http://ocsigen.org/docu/1.3.0/Lwt_process.html
let process_output_to_list2 = fun command ->
let chan = Unix.open_process_in command in
let res = ref ([] : string list) in
let rec process_otl_aux () =
let e = input_line chan in
res := e::!res;
process_otl_aux() in
try process_otl_aux ()
with End_of_file ->
let stat = Unix.close_process_in chan in (List.rev !res,stat)
let cmd_to_list command =
let (l,_) = process_output_to_list2 command in l
There are lots of examples on PLEAC.
You can use the third party library Rashell which uses Lwt to define some high-level primitives to read output from processes. These primitives, defined in the module Rashell_Command, are:
exec_utility to read the output of a process as a string;
exec_test to only read the exit status of a process;
exec_query to read the output of a process line by line as a string Lwt_stream.t
exec_filter to use an external program as a string Lwt_stream.t -> string Lwt_stream.t transformation.
The command function is used to create command contexts on which the previous primitives can be applied, it has the signature:
val command : ?workdir:string -> ?env:string array -> string * (string array) -> t
(** [command (program, argv)] prepare a command description with the
given [program] and argument vector [argv]. *)
So for instance
Rashell_Command.(exec_utility ~chomp:true (command("", [| "uname" |])))
is a string Lwt.t which returns the “chomped” string (new line removed) of the “uname” command. As a second example
Rashell_Command.(exec_query (command("", [| "find"; "/home/user"; "-type"; "f"; "-name"; "*.orig" |])))
is a string Lwt_stream.t whose elements are the paths of the file found by the command
find /home/user -type f -name '*.orig'
The Rashell library defines also interfaces to some commonly used commands, and a nice interface to the find command is defined in Rashell_Posix – which by the way guarantees POSIX portability.

Resources