Following the example here: https://nim-by-example.github.io/arrays/ and I am printing out an array. In the example they print the matrix, but the echo does not work and I get the following error:
matrix.nim(20, 7) Error: type mismatch: got (Matrix[2, 2])
but expected one of:
system.$(x: T)
system.$(x: Enum)
system.$(x: int64)
system.$(x: bool)
system.$(x: char)
system.$(x: float)
system.$(x: string)
system.$(x: seq[T])
system.$(x: int)
system.$(x: uint64)
system.$(x: set[T])
I'm assuming this is versioning issue (I have im Compiler Version 0.12.0 installed on Ubuntu - probably not the latest).
However is there a smart way to print entities of any type. Is there a pprint as there is in Python?
The $ operator referenced in the error message is Nim's "to string" operator. echo expects that such an operator is defined for the passed in type. It just happens that the latest version of the Nim's system module doesn't include a definition of $ for the array type.
You can easily fix the code by adding the following definition in your own module:
proc `$`[T,R](m: Matrix[T,R]): string =
result = ""
for r in countup(1, m.H):
for c in countup(1, m.W):
if c != 1: result.add " "
result.add $m[r][c]
result.add "\n"
This results in the expected output:
1 1
1 1
The closest thing to an universal printing operator is the Nim's repr proc, which tries to return the standard Nim's syntax representation of the values or the marshal module, which can encode an arbitrary type in json:
var sum = mat1 + mat2
echo sum.repr
import marshal
echo $$sum
In this particular example, both options yield the same result:
[[1, 1], [1, 1]]
[[1, 1], [1, 1]]
Related
I am trying to convert the price field, which is a string (eg "2.22" or "") to a float or nil, and then add it to the database.
def insert_product_shop(conn, product_id, shop_id, price) do
priceFloat = nil
if price not in [""] do
price = elem(Float.parse(price), 0)
priceFloat = price / 1
IO.inspect(priceFloat)
else
priceFloat = nil
end
IO.inspect(priceFloat)
changeset = Api.ProductShop.changeset(%Api.ProductShop{
p_id: product_id,
s_id: shop_id,
price: priceFloat,
not_in_shop_count: 0,
is_in_shop_count: 0
})
errors = changeset.errors
valid = changeset.valid?
IO.inspect(changeset)
case insert(changeset) do
{:ok, product_shop} ->
{:ok, product_shop}
{:error, changeset} ->
{:error, :failure}
end
end
the output is:
2.22
nil
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #Api.ProductShop<>,
valid?: true>
13:25:41.745 [debug] QUERY OK db=2.0ms
INSERT INTO "product_shops" ("is_in_shop_count","not_in_shop_count","p_id","s_id") VALUES ($1,$2,$3,$4) RETURNING "id" [0, 0, 40, 1]
As the output shows, priceFloat becomes nil, I assume because when I set it to 2.22 it was out of scope. Maybe my code is too imperative. How can I rewrite this to convert "2.22" to 2.22 without making it nil, and allow "" to be converted to nil?
As the output shows, priceFloat becomes nil, I assume because when I set it to 2.22 it was out of scope.
Almost right. Rather that the variable you are trying to set being out of scope, the problem is that the variable you assign to inside the if statement goes out of scope. It just happens to have the same name as the variable outside the if statement.
The solution is to assign the result of the if/else statement to the variable. Here is your code with minimal changes:
price = "2.22"
priceFloat =
if price not in [""] do
elem(Float.parse(price), 0)
else
nil
end
IO.inspect(priceFloat)
However, it's still not very idiomatic. You can take advantage of the fact that Float.parse/1 returns :error when the input is the empty string to write it like with a case expression:
priceFloat =
case Float.parse(price) do
{float, ""} -> float
:error -> nil
end
You can use case to evaluate the returned value by Float.parse and assign nil when it returns :error, assuming that the purpose of your if is to avoid the parsing error
def insert_product_shop(conn, product_id, shop_id, price) do
priceFloat = case Float.parse(price) do
{value, _remainder} -> value
:error -> nil
end
...
end
You can use a combination of pattern matching and method overloading to solve the problem:
defmodule Example do
def parsePrice(""), do: nil
def parsePrice(price) when is_float(price), do: price
def parsePrice(price) when is_binary(price) do
{float, _} = Float.parse(price)
float
end
end
Example.parsePrice(2.22) |> IO.inspect
Example.parsePrice("2.22") |> IO.inspect
(The equivalent is achievable using a case statement)
If you pass anything that is not a binary (a string) or a float to this function it will cause a pattern unmatched error. This may be good in case you have some error reporting in place, so you can detect unexpected usage of your code.
For a better debugging experience, I encourage you to use the built-in debugger via IEx.pry/0.
For the sake of diversity, I’d post another approach that uses with/1 special form.
with {f, ""} <- Float.parse("3.14"),
do: f,
else: (_ -> nil)
Here we explicitly match the float only. Any trailing garbage would be discarded. If the match succeeds, we return the float, otherwise, we return nil.
Beware of Float.parse/1 might be confused by garbage that looks like scientific notation.
(with {f, ""} <- Float.parse("3e14"), do: f) == 300_000_000_000_000
#⇒ true
Important sidenote: assigning priceFloat inside if does not change the value of the priceFloat variable outside of the scope. Scoping in elixir is pretty important and one cannot propagate local variables to the outermost scope, unlike most of the languages.
foo = 42
if true, do: foo = 3.14
IO.puts(foo)
#⇒ 42
Well, to some extent it’s possible to affect outermost scope variables from macros with var!/2, and if is indeed a macro, but this whole stuff is definitely far beyond the scope of this question.
I'm trying to write my first Swift program, and I know this question has been asked before, but the answers using split aren't working for me. I'm using Xcode 6.4 and Swift 1.2.
I have a String named line.
If I write
let inputs = split(line) {$0 = " "}
as suggested at Swift: Split a String into an array, I get the error message "Cannot invoke 'split' with an argument list of type (String, ()->)"
If I write
let inputs = split(line, {find(" ",$0) != nil}, allowEmptySlices: false)
as suggested at split now complains about missing "isSeparator", I get the error message, "Missing argument for parameter 'isSeparator' in call."
If I jump to the definition of split, I find
func split<S : Sliceable, R : BooleanType>(elements: S, maxSplit: Int = default, allowEmptySlices: Bool = default, #isSeparator: #noescape (S.Generator.Element) -> R) -> [S.SubSlice]
I don't understand what the type of the last parameter is, which is perhaps the root of my problem. Can you tell me how I should call split, and even better can you explain what the parameter type is? Why isn't the type simply (S)->R? I am getting the line from a generator that reads a file line-by-line, if that makes any difference.
for line:String in reader! {
let inputs = split(line) {$0 = " "}
...
}
As said in the comments to the question, the correct way is to use the == operator instead of =.
The type (S.Generator.Element) -> R) must be interpreted in the light of the definition of split:
func split<S : Sliceable, R : BooleanType>
(elements: S,
maxSplit: Int = default,
allowEmptySlices: Bool = default,
#isSeparator: #noescape (S.Generator.Element) -> R)
-> [S.SubSlice]
The type of split is a generic one: in other words, it is a function that can take as first parameter any value that satisfy a generic type (or protocol) subtype of Sliceable, like String, and return a result which must be a subtype of BooleanType (for instance true or false, which are instances of Bool). So the last parameter is a function which gets as parameter a type which is Element of Generator of S (for instance Character) and returns a value of type R. And {$0 == " "} is exactly a predicate of this type, that has an (implicit) parameter ($0), and check if it is equal to the character " ".
I have a Maxima program that does some algebra and then writes some things down on an external file. How do I include some calculated values and even small expressions into the name of the file?
A mwe would be the following:
N:3;
f: erf(x);
tay: taylor(f,x,0,N);
with_stdout("taylor.txt", fortran(tay));
But this example names the file taylor.txt. I wanted something that named the file taylor_N3_f_erf.txt or something like that. I have tried several syntaxes but nothing worked.
Also, I know Maxima in programmed in lisp and I learned the syntax for concatenating strings in Lisp but I haven't figured out how to use that in Maxima.
Thank you very much.
Here's what I came up with. It took some playing around with argument quoting and evaluation in functions but I think it works now.
(%i2) bar (name_base, name_extension, ['vars]) := sconcat (name_base, foo(vars), ".", name_extension) $
(%i3) foo(l) := apply (sconcat, join (makelist ("_", 2 * length (l)), join (l, map (string, map (ev, l))))) $
(%i4) [a, b, c] : [123, '(x + 1), '(y/2)];
y
(%o4) [123, x + 1, -]
2
(%i5) bar ("foobar", "txt", a, b, c);
(%o5) foobar_a_123_b_x+1_c_y/2.txt
(%i6) myname : bar ("baz", "quux", a, b);
(%o6) baz_a_123_b_x+1.quux
(%i7) with_stdout (myname, print ("HELLO WORLD"));
(%o7) HELLO WORLD
(%i8) printfile ("baz_a_123_b_x+1.quux");
HELLO WORLD
(%o8) baz_a_123_b_x+1.quux
Note that sconcat concatenates strings and string produces a string representation of an expression.
Division expressions could cause trouble since / means a directory in a file name ... maybe you'll have to subsitute for those characters or any other non-allowed characters. See ssubst.
Note that with_stdout evaluates its first argument, so if you have a variable e.g. myname then the value of myname is the name of the output file.
I'm trying to parse a mathematical expression using pyparsing. I know i could just copy the example calculator from pyparsing site, but i want to understand it so i can add to it later. And i'm here because i tried to understand the example, and i couldn't, so i tried my best, and i got to this:
symbol = (
pp.Literal("^") |
pp.Literal("*") |
pp.Literal("/") |
pp.Literal("+") |
pp.Literal("-")
)
operation = pp.Forward()
atom = pp.Group(
pp.Literal("(").suppress() + operation + pp.Literal(")").suppress()
) | number
operation << (pp.Group(number + symbol + number + pp.ZeroOrMore(symbol + atom)) | atom)
expression = pp.OneOrMore(operation)
print(expression.parseString("9-1+27+(3-5)+9"))
That prints:
[[9, '-', 1, '+', 27, '+', [[3, '-', 5]], '+', 9]]
It works, kinda. I want precedence and all sorted into Groups, but after trying a lot, i couldn't find a way to do it. More or less like this:
[[[[9, '-', 1], '+', 27], '+', [3, '-', 5]], '+', 9]
I want to keep it AST-looking, i would like to generate code from it.
I did saw the operatorPrecedence class? similar to Forward, but i don't think i understand how it works either.
EDIT:
Tried more in depth operatorPrecedence and i got this:
expression = pp.operatorPrecedence(number, [
(pp.Literal("^"), 1, pp.opAssoc.RIGHT),
(pp.Literal("*"), 2, pp.opAssoc.LEFT),
(pp.Literal("/"), 2, pp.opAssoc.LEFT),
(pp.Literal("+"), 2, pp.opAssoc.LEFT),
(pp.Literal("-"), 2, pp.opAssoc.LEFT)
])
Which doesn't handle parenthesis (i don't know if i will have to postprocess the results) and i need to handle them.
The actual name for this parsing problem is "infix notation" (and in recent versions of pyparsing, I am renaming operatorPrecedence to infixNotation). To see the typical implementation of infix notation parsing, look at the fourFn.py example on the pyparsing wiki. There you will see an implementation of this simplified BNF to implement 4-function arithmetic, with precedence of operations:
operand :: integer or real number
factor :: operand | '(' expr ')'
term :: factor ( ('*' | '/') factor )*
expr :: term ( ('+' | '-') term )*
So an expression is one or more terms separated by addition or subtraction operations.
A term is one or more factors separated by multiplication or division operations.
A factor is either a lowest-level operand (in this case, just integers or reals), OR an expr enclosed in ()'s.
Note that this is a recursive parser, since factor is used indirectly in the definition of expr, but expr is also used to define factor.
In pyparsing, this looks roughly like this (assuming that integer and real have already been defined):
LPAR,RPAR = map(Suppress, '()')
expr = Forward()
operand = real | integer
factor = operand | Group(LPAR + expr + RPAR)
term = factor + ZeroOrMore( oneOf('* /') + factor )
expr <<= term + ZeroOrMore( oneOf('+ -') + term )
Now using expr, you can parse any of these:
3
3+2
3+2*4
(3+2)*4
The infixNotation pyparsing helper method takes care of all the recursive definitions and groupings, and lets you define this as:
expr = infixNotation(operand,
[
(oneOf('* /'), 2, opAssoc.LEFT),
(oneOf('+ -'), 2, opAssoc.LEFT),
])
But this obscures all the underlying theory, so if you are trying to understand how this is implemented, look at the raw solution in fourFn.py.
[EDIT - 18 Dec 2022] For those looking for a pre-defined solution, I've packaged infixNotation up into its own pip-installable package called plusminus. plusminus defines a BaseArithmeticParser class for creating a ready-to-run parser and evaluator that supports these operators:
** ÷ >= ∈ in ?:
* + == ∉ not |absolute-value|
// - != ∩ and
/ < ≠ ∪ ∧
mod > ≤ & or
× <= ≥ | ∨
And these functions:
abs ceil max
round floor str
trunc min bool
The BaseArithmeticParser class allows you to define additional operators and functions for your own domain-specific expressions, and the examples show how to define parsers with custom functions and operators for dice rolling, retail price discounts, among others.
I'm learning Prolog and I need idea how to convert a list of strings:
['f(a,45)', 'f(b,13)', 'f(c,12)']
into a list of pairs that looks like this:
[[45,'a'],[13,'b'],[12,'c']]
That's a list of atoms, not strings. Strings in Prolog are usually list of character codes, expressed like
["f(a,45)", "f(b,13)", "f(c,12)"]
Anyway, apply a conversion to each element with a recursive function:
convert([], []).
convert([Atom|Atoms], [Pair|Pairs]) :-
convert_element(Atom, Pair),
convert(Atoms, Pairs).
Instead of recursion you could use maplist/3 in this way:
convert(As, Ps) :- maplist(convert_element, As, Ps).
To convert an element, you need a parser. DCGs are convenient:
convert_element(Atom, [N, A]) :-
atom_codes(Atom, Codes),
phrase(("f(", atomc(Ac), ",", numc(Nc), ")"), Codes, []),
atom_codes(A, Ac),
number_codes(N, Nc).
atomc(A) --> ([C], {is_lowerc(C)}, atomc(Cs), {A = [C|Cs]}) ; {A = []}.
numc(N) --> ([C], {is_numc(C)}, numc(Cs), {N = [C|Cs]}) ; {N = []}.
is_lowerc(C) :- C #>= 0'a, C #=< 0'z.
is_numc(C) :- C #>= 0'0, C #=< 0'9.
test:
?- convert(['f(a,45)', 'f(b,13)', 'f(c,12)'],L).
L = [[45, a], [13, b], [12, c]] .
atomc//1 & numc//1 are expressed in a compact way, but are very simple recursive pattern matching procedures, i.e. atomc//1 could be
atomc([C|Cs]) --> [C], {is_lowerc(C)}, !, atomc(Cs).
atomc([]) --> [].
Alternatively, you can use this code :
convert :-
L = ["f(a,45)", "f(b,13)", "f(c,12)"],
maplist(extract_args,L, LA),
writeln(LA).
extract_args(S, [A1,A2]) :-
string_to_atom(S, A),
term_to_atom(T, A),
T =..[_, A2, A1].
If you have atoms, just use term_to_atom/2 in extract_args/2.