I'm defining a TestList (HUnit) and want to spread the definition over multiple lines. I came to the following solution:
tests = TestList ([TestLabel "test1" test1] ++
[TestLabel "test2" test2] ++
[TestLabel "test3" test3] ++
[TestLabel "test4" test4] ++
[TestLabel "test5" test5])
Is the use of the ++ operator the proper way to do such things?
Are there better or more elegant ways to do this?
I'd write
tests = TestList
[ TestLabel "test1" test1
, TestLabel "test2" test2
, TestLabel "test3" test3
, TestLabel "test4" test4
, TestLabel "test5" test5 ]
There's still place for improvements for #ephemient variant: don't use TestLabel at all, use ~: shortcut:
tests = TestList
[ "test1" ~: test1
, "test2" ~: test2
, "test3" ~: test3
, "test4" ~: test4
, "test5" ~: test5 ]
Note that there are more operators to construct assertions: #?, #=?, #?=. See http://hunit.sourceforge.net/HUnit-1.0/Guide.html or http://hackage.haskell.org/package/HUnit for details. The shortcuts use priorities and type classes cleverly, so you will get much less parentheses noise at the cost of slightly worse error messages.
Maybe I'm missing something, but why not just commas? This doesn't seem particularly unlike a normal list.
tests = TestList ([TestLabel "test1" test1,
TestLabel "test2" test2,
TestLabel "test3" test3,
TestLabel "test4" test4,
TestLabel "test5" test5])
Related
I have an API that executes some KQL.
I'm executing a KQL that filters all rows such that some column (that is of type list of string) contains any of the values in some given list of strings.
Basically:
let foo1 = datatable(d: dynamic) [
dynamic([""]),
dynamic(["foobar"]),
dynamic(["Alice", "Bob"]),
dynamic(["Alice"])
];
foo1
| where d has_any (dynamic(["Alice", "otherthing"]))
Which outputs the last 2 rows as I expect - I wanted all rows where d has any of the values "Alice", "otherthing".
Everything works as expected, until I want all rows that contain the empty string value:
let foo1 = datatable(d: dynamic) [
dynamic([""]),
dynamic(["foobar"]),
dynamic(["Alice", "Bob"]),
dynamic(["Alice"])
];
foo1
| where d has_any (dynamic([""]))
and the result above outputs all rows, instead of only the first row, which has the empty string value.
Why?
What can I change in order for it to work as I expect it?
1.
Apparently any string has the empty string, e.g.:
print "abc" has ""
print_0
true
Fiddle
2.
It seems you are looking for a full match and not a partial match.
In this case, has might lead to undesired results, e.g.:
print dynamic(["The story of Alice in wonderland", "Bob"]) has "Alice"
print_0
true
Fiddle
Solution:
set_intersect()
let foo1 = datatable(d: dynamic) [
dynamic([""]),
dynamic(["foobar"]),
dynamic(["Alice", "Bob"]),
dynamic(["Alice"])
];
foo1
| where array_length(set_intersect(dynamic(["Alice", "otherthing"]), d)) > 0
d
["Alice","Bob"]
["Alice"]
Fiddle
let foo1 = datatable(d: dynamic) [
dynamic([""]),
dynamic(["foobar"]),
dynamic(["Alice", "Bob"]),
dynamic(["Alice"])
];
foo1
| where array_length(set_intersect(dynamic([""]), d)) > 0
d
[""]
Fiddle
I have a function that given an Int returns a list of lists of Strings.
fetchParts :: Int -> [[String]]
This is what the output looks like
[["title", "some title"], ["rate", "2.4"], ["dist", "some string"], ["tr", "1"], ["td, "2"] ..]]
The length of the output can be variable. Only the first 3 lists can be present 100% of the time.
The later part of the list can be
["a", "1"], ["b", "2"] ..
or
["some", "1"], ["part", "2"], ["of", "3"] ..]
or
["ex1", "a"], ["ex2", "b"], ..]
or some other combination of strings.
And I want to add this output to a sqlite3 database file. I'm using HDBC and HDBC.Sqlite3 for this.
To add something to a database file I'm running functions like these
initialConnection <- connectSqlite3 "src/parts.db"
run initialConnection partsEntry []
commit initialConnection
disconnect initialConnection
where partsEntry is a simple SQL String like this
partsEntry = "INSERT INTO PARTSDATA ( title, rate, dist, ...) VALUES ( "some title", "2.4", "some string", ...)
where
( title, rate, dist, ...) are from head <$> fetchParts 1
and
("some title", "2.4", "some string" ...) are from last <$> fetchParts 1
The problem is say if "some" column doesn't exists, code will throw errors.
What I want to do is something like this
if column "abc" doesn't exists, add column "abc" and insert
"this" value at the current row
if column "abc" exists, just insert "this" value at the current row
But I'm not sure how to go about doing that.
I was able to solve the problem.
First use describeTable function from HDBC package. The function will return column names and type. If you just need the names like I did, this is what you can do
getColumnsInTable :: conn -> String -> IO [String]
getColumnsInTable conn tableName = do
d <- describeTable conn tableName
return $ fst <$> d
The return will have all the columns' names.
Scan through the list to see if it contains all the columns you wish. If it doesn't use a function like the following to alter the table, i.e. add a new column with INT type.
createNewColumn conn columnName = do
let stmt = "ALTER TABLE FantasyBooks ADD COLUMN " ++ columnName ++ " INT;"
run conn stmt []
I've chosen to center this question around JSON objects and wl-pprint-annotated (here is the paper behind that library) because they make it easy to have an MVCE, but my problem is not actually around pretty-printing just JSON objects and I am flexible for which pretty-printing library I use.
Consider the following simplified JavaScript object data type:
data Object = Object [(String, Object)]
| String String
How can I defined a pretty-printing function that wraps its output to multiple lines in the usual way? What I mean by that is: the pretty-printed output should, whenever possible fit on one line. When that is not possible, I expect the outermost objects to start adding newlines before the inner ones.
Here is one attempt using wl-pprint-annotated:
{-# LANGUAGE OverloadedString #-}
import Text.PrettyPrint.Annotated.WL
prettyObject :: Object -> Doc a
prettyObject (String str) = "\"" <> text str <> "\""
prettyObject (Object fields) = Union ("{" <+> hsep fields' <+> "}")
("{" <#> indent 2 (vsep fields') <#> "}")
where
fields' :: [Doc a]
fields' = punctuate "," [ text key <> ":" <+> prettyObject val
| (key,val) <- fields ]
Now, some test cases.
ghci> o1 = Object [("key1", String "val1")]
ghci> o2 = Object [("key2", String "val2"), ("looooooooooong key3", String "loooooooooooong val3"),("key4", String "val4")]
ghci> o3 = Object [("key5", String "val5"), ("key6", o2), ("key7", String "val7")]
ghci> prettyObject o1
{ key1: "val1" }
ghci> prettyObject o2
{
key2: "val2",
looooooooooong key3: "loooooooooooong val3",
key4: "val4"
}
ghci> prettyObject o3
{ key5: { key1: "val1" }, key6: {
key2: "val2",
looooooooooong key3: "loooooooooooong val3",
key4: "val4"
}, key7: "val7" }
I would like the last output to instead be
{
key5: { key1: "val1" },
key6: {
key2: "val2",
looooooooooong key3: "loooooooooooong val3",
key4: "val4"
},
key7: "val7"
}
I am looking for a solution which somehow fits with one of the existing pretty-printing libraries in Haskell (in reality, I'm pretty-printing much more than just a subset of JSON).
I am not looking for a solution which defines a prettyObject :: Object -> String - the whole point of this approach is that the rendering of the Doc depends on where it is in the big picture of what is being pretty-printed.
The pretty print library you are using can already do this; (you have just told it to do a different thing!) generally this family (WL) of pretty printers handles this case pretty well.
Note the positioning of your Union:
prettyObject (Object fields) = Union <one line> <many line>
At the point in your text where you are logically making the choice to break, which is at the beginning of a key-value pair, you don't have a Union in your Doc structure. The choice is made at the point where a {..} enclosed block begins; and if you scrutinize the output, that is exactly what it gives you:
{ key5: { key1: "val1" }, key6: { ----- line break here
key2: "val2",
You need a function to implement your desired logic for key-value pairs:
indent' k x = flatAlt (indent k x) (flatten x)
prettyKVPair (k,v) = indent' 2 $ text k <> ":" <+> pretty v
indent' is like indent, but provides an explicit alternative which is not indented. flatAlt provides an alternative which is used when the text is flattened, and your text will be flattened by (you may have guessed) flatten. You also need to re-structure prettyObject accordingly:
prettyObject :: Object -> Doc a
prettyObject (Object fields) = sep $ "{" : fields' ++ [ "}" ] where
fields' = punctuate "," $ map prettyKVPair fields
...
Note there is no explicit Union, but sep = group . vsep and group = \x -> Union (flatten x) x. You now have a union corresponding to logical choices about where you flatten your text.
The result:
>pretty o1
{ key1: "val1" }
>pretty o2
{
key2: "val2",
looooooooooong key3: "loooooooooooong val3",
key4: "val4"
}
>pretty o3
{
key5: "val5",
key6: {
key2: "val2",
looooooooooong key3: "loooooooooooong val3",
key4: "val4"
},
key7: "val7"
}
In response to the question in the comment, the way to provide a flat alternative is to use flatAlt, of course! The only issue here is you want to do this for a single element (the last one) of a list - but this is an issue with lists, not Doc. Feel free to use Data.Sequence or any other Traversable, with which most of the 'list-like' functions like punctuate work, if this is an operation you need a lot.
flattenedOf a b = flatAlt a (flatten b) # useful combinator
trailingSep _ [] = []
trailingSep s xs = as ++ [ (a <> s) `flattenedOf` a ]
where as = init xs; a = last xs
...
prettyObject (Object fields) = <unchanged> where
fields' = trailingSep "," $ <unchanged>
I am new in elixir development. I have problem with parsing of string in elixir. Assume that I have string "Hello World from the hell". I know that I can split this like this String.split("Hello World from the hell"). I would like to know is the anyway to assign element of this string to list in elixir?
String.split/1 returns a list - one of Elixir's fundamental data structures, along with maps and tuples. A list is your go-to basic collection in Elixir. Even though internally it's a linked list, you can perform all sorts of operations on it using functions from the Enum module:
$ iex
iex(1)> ls = String.split("Hello World from the hell")
["Hello", "World", "from", "the", "hell"]
iex(2)> i ls
Term
["Hello", "World", "from", "the", "hell"]
Data type
List
Reference modules
List
iex(3)> Enum.take(ls, 2)
["Hello", "World"]
iex(4)> Enum.at(ls, 4)
"hell"
iex(5)> [l0, l1, l2, l3, l4] = ls
["Hello", "World", "from", "the", "hell"]
iex(6)> l4
"hell"
iex(7)> Enum.take(ls, 4) ++ ["iex", "shell"]
["Hello", "World", "from", "the", "iex", "shell"]
As you can see Enum.at/3 gives you something similar to the a[i] style array access.
If you're worried about the efficiency of finding an element in your list - for example your input string is going to be something much longer than "Hello World from the hell" and you'll be getting elements from it by index many times, essentially traversing it each time, you can build a map from it instead, and look the words by indices efficiently:
iex(8)> with_indices = Enum.with_index(ls)
[{"Hello", 0}, {"World", 1}, {"from", 2}, {"the", 3}, {"hell", 4}]
iex(9)> indices_and_words = Enum.map(with_indices, fn({a, b}) -> {b, a} end)
[{0, "Hello"}, {1, "World"}, {2, "from"}, {3, "the"}, {4, "hell"}]
iex(10)> map = Map.new(indices_and_words)
%{0 => "Hello", 1 => "World", 2 => "from", 3 => "the", 4 => "hell"}
iex(11)> map[0]
"Hello"
iex(12)> map[4]
"hell"
I (New to Haskell ) want to find if a word in line (of lines) is present or not. I saw few functions to achieve it like : elem, isInfixOf
Prelude DL> isInfixOf "new" "I am new to Haskell"
True
Prelude DL> elem "new" ["I am", "new to", "Haskell"]
False
How can I implement 'isInfixOf' on every string within list of strings.
If you expect to get true:
any (isInfixOf "new") ["I am", "new to", "Haskell too!"]
If you want a list of Bool:
map (isInfixOf "new") ["I am", "new to", "Haskell too!"]
You do this by mapping the isInfixOf function over a list of Strings like so:
ghci>> map (isInfixOf "new") ["I am", "new to", "Haskell"]
[False, True, False]
map evaluates the predicate for each element in the list.
Building from this, you can use other functions from Data.List to find out more about the list as a whole:
ghci>> any (isInfixOf "new") ["I am", "new to", "Haskell"]
True
ghci>> all (isInfixOf "new") ["I am", "new to", "Haskell"]
False