Elixir - undefined function do_match/4 - ecto
To refactor, I'm trying to move code out of my router into controllers.
I'm getting this error when I do so:
== Compilation error on file lib/api/controllers/product.ex ==
** (CompileError) lib/plug/router.ex:211: undefined function do_match/4
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
controller
defmodule Api.Controllers.Product do
use Plug.Router
import Api.ProductCategory
alias Api.ProductCategory, as: ProductCategory
import Api.Product
import Api.Shop
alias Api.Shop, as: Shop
alias Api.Product, as: Product
import Api.ProductShop
alias Api.ProductShop, as: ProductShop
import Api.Subcategory
alias Api.Subcategory, as: Subcategory
import Api.Category
alias Api.Category, as: Category
import Ecto.Query
import Api.Repo
def put_product(conn) do
errors = {}
# IO.inspect(conn.body_params)
# IO.inspect(conn.query_params["p_id"])
product = Api.Product |> Api.Repo.get(conn.query_params["p_id"])
shop = Api.Shop |> Api.Repo.get(conn.query_params["s_id"])
params = for key <- ~w(image description),
value = conn.body_params[key], into: %{},
do: {key, value}
changeset = Api.Product.changeset(product, params)
case Api.Repo.update(changeset) do
{:ok, product} ->
errors = Tuple.append(errors, "Product updated")
{:error, changeset} ->
errors = Tuple.append(errors, "Product not updated")
end
pid = conn.query_params["p_id"]
sid = conn.query_params["s_id"]
price = conn.body_params["price"]
product_shop = Api.Repo.get_by(ProductShop, s_id: sid, p_id: pid)
IO.inspect(product_shop)
changeset2 = Api.ProductShop.changeset(product_shop, %{price: price})
case Api.Repo.update(changeset2) do
{:ok, product_shop} ->
errors = Tuple.append(errors, "Price updated")
{:error, changeset2} ->
errors = Tuple.append(errors, "Price not updated")
end
IO.inspect(errors)
conn
|> put_resp_content_type("application/json")
|> send_resp(200, Poison.encode!(%{
successs: "success",
errors: Tuple.to_list(errors)
}))
end
end
router.ex
defmodule Api.Router do
use Plug.Router
import Api.ProductCategory
alias Api.ProductCategory, as: ProductCategory
import Api.Product
import Api.Shop
alias Api.Shop, as: Shop
alias Api.Product, as: Product
import Api.ProductShop
alias Api.ProductShop, as: ProductShop
import Api.Subcategory
alias Api.Subcategory, as: Subcategory
import Api.Category
alias Api.Category, as: Category
import Ecto.Query
import Api.Controllers.Product
alias Api.Controllers.Product, as: ProductController
if Mix.env == :dev do
use Plug.Debugger
end
plug :match
plug Plug.Parsers, parsers: [:json],
pass: ["application/json"],
json_decoder: Poison
plug :dispatch
get "/favicon.ico" do
# get_categories(conn)
end
get "/categories/" do
get_categories(conn)
end
options "/categories/" do
get_categories(conn)
end
....
put "/products" do
ProductController.put_product(conn)
end
...
What is causing the error?
Full error:
Benjamins-MacBook-Pro:api Ben$ iex -S mix
Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 2 files (.ex)
warning: the variable "errors" is unsafe as it has been set inside a case/cond/receive/if/&&/||. Please explic
itly return the variable value instead. For example:
case int do
1 -> atom = :one
2 -> atom = :two
end
should be written as
atom =
case int do
1 -> :one
2 -> :two
end
Unsafe variable found at:
lib/api/controllers/product.ex:54
warning: the variable "errors" is unsafe as it has been set inside a case/cond/receive/if/&&/||. Please explic
itly return the variable value instead. For example:
case int do
1 -> atom = :one
2 -> atom = :two
end
should be written as
atom =
case int do
1 -> :one
2 -> :two
end
Unsafe variable found at:
lib/api/controllers/product.ex:56
warning: the variable "errors" is unsafe as it has been set inside a case/cond/receive/if/&&/||. Please explic
itly return the variable value instead. For example:
case int do
1 -> atom = :one
2 -> atom = :two
end
should be written as
atom =
case int do
1 -> :one
2 -> :two
end
Unsafe variable found at:
lib/api/controllers/product.ex:59
lib/api/controllers/product.ex:59
warning: the variable "errors" is unsafe as it has been set inside a case/cond/receive/if/&&/||. Please explic
itly return the variable value instead. For example:
case int do
1 -> atom = :one
2 -> atom = :two
end
should be written as
atom =
case int do
1 -> :one
2 -> :two
end
Unsafe variable found at:
lib/api/controllers/product.ex:65
warning: variable "shop" is unused
lib/api/controllers/product.ex:30
warning: variable "product" is unused
lib/api/controllers/product.ex:38
warning: variable "changeset" is unused
lib/api/controllers/product.ex:40
warning: variable "product_shop" is unused
lib/api/controllers/product.ex:53
warning: variable "changeset2" is unused
lib/api/controllers/product.ex:55
== Compilation error on file lib/api/controllers/product.ex ==
** (CompileError) lib/plug/router.ex:211: undefined function do_match/4
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
You're getting the do_match error because your module uses Plug.Router but does not define any route. do_match function clauses are added by the get/post/etc macros in Plug.Router. With no routes, no function clause is ever defined causing that error. Since you don't actually want to define any routes in the module, you can just remove use Plug.Router.
You're also missing an import for the put_resp_content_type/2 function. Adding import Plug.Conn should fix that.
Related
How to get function name as string in macro/template?
Can't figure out how to get function name as string in macro. The code below should generate rlisten("multiply", multiply) but it won't compile, playground. import macros proc rlisten*[A, B, R](fn: string, op: proc(a: A, b: B): R): void = echo fn macro remotefn(fn): void = quote do: rlisten($`fn`, `fn`) # It should generte `rlisten("multiply", multiply)` proc multiply(a, b: int): int = discard remotefn multiply
First you need to accept typed or untyped parameters to a macro. In this particular case you need to use typed argument in order to be able to access the function symbol (symbols are identifiers replaced by type resolution pass of the compiler). import macros proc rlisten*[A, B, R](fn: string, op: proc(a: A, b: B): R): void = echo fn macro remotefn(fn: typed): void = echo fn.treeRepr() # ^ Show tree representation of the argument. In this particular case it is just a # single function symbol. let name = fn.strVal() echo "Function name is ", name proc multiply(a, b: int): int = discard remotefn multiply Outputs Sym "multiply" Function name is multiply
js_of_ocaml calling a function in ocaml from js
I have a function that uses a mutable variable that takes strings and returns strings. (its a read eval print loop interpreter) I tried exporting it as such: let () = Js.export_all (object%js method js_run_repl = Js.wrap_callback js_run_repl end) Heres a snippet of the function im exporting let js_run_repl str = match String.(compare str "quit") with | 0 -> "bye" | _ -> ... regardless of my input it always returns bye, calling the function directly in ocaml produced the expected behaviour. Heres the output from node: > var mod = require('./main.bc'); undefined > mod.js_run("constant P : Prop"); MlBytes { t: 0, c: 'bye', l: 3 } > Its also peculiar why the function is called js_run instead of js_run_repl. the latter is undefined according to node.
let () = Js.export_all (object%js method js_run_repl str = str |> Js.to_string |> js_run_repl |> Js.string end) I had to convert the strings explicitly to ocaml strings and back to js
Mapping sub-sets of parentheses to chars
I am attempting to create a Scala method that will take one parent group of parentheses, represented as a String, and then map each subgroup of parentheses to a different letter. It should then put these in a map which it returns, so basically I call the following method like this: val s = "((2((x+3)+6)))" val map = mapParentheses(s) Where s could contain any number of sets of parentheses, and the Map returned should contain: "(x+3)" -> 'a' "(a+6)" -> 'b' "(2b)" -> 'c' "(c)" -> 'd' So that elsewhere in my program I can recall 'd' and get "(c)" which will become "((2b))" then ((2(a+6))) and finally ((2((x+3)+6))). The string sent to the method mapParentheses will never have unmatched parentheses, or extra chars outside of the main parent parentheses, so the following items will never be sent: "(fsf)a" because the a is outside the parent parentheses "(a(aa))(a)" because the (a) is outside the parent parentheses "((a)" because the parentheses are unmatched ")a(" because the parentheses are unmatched So I was wondering if anyone knew of an easy (or not easy) way of creating this mapParentheses method.
You can do this pretty easily with Scala's parser combinators. First for the import and some simple data structures: import scala.collection.mutable.Queue import scala.util.parsing.combinator._ sealed trait Block { def text: String } case class Stuff(text: String) extends Block case class Paren(m: List[(String, Char)]) extends Block { val text = m.head._2.toString def toMap = m.map { case (k, v) => "(" + k + ")" -> v }.toMap } I.e., a block represents a substring of the input that is either some non-parenthetical stuff or a parenthetical. Now for the parser itself: class ParenParser(fresh: Queue[Char]) extends RegexParsers { val stuff: Parser[Stuff] = "[^\\(\\)]+".r ^^ (Stuff(_)) def paren: Parser[Paren] = ("(" ~> insides <~ ")") ^^ { case (s, m) => Paren((s -> fresh.dequeue) :: m) } def insides: Parser[(String, List[(String, Char)])] = rep1(paren | stuff) ^^ { blocks => val s = blocks.flatMap(_.text)(collection.breakOut) val m = blocks.collect { case Paren(n) => n }.foldLeft(List.empty[(String, Char)])(_ ++ _) (s, m) } def parse(input: String) = this.parseAll(paren, input).get.toMap } Using get in the last line is very much not ideal, but is justified by your assertion that we can expect well-formed input. Now we can create a new parser and pass in a mutable queue with some fresh variables: val parser = new ParenParser(Queue('a', 'b', 'c', 'd', 'e', 'f')) And now try out your test string: scala> println(parser parse "((2((x+3)+6)))") Map((c) -> d, (2b) -> c, (a+6) -> b, (x+3) -> a) As desired. A more interesting exercise (left to the reader) would be to thread some state through the parser to avoid the mutable queue.
Classic recursive parsing problem. It can be handy to hold the different bits. We'll add a few utility methods to help us out later. trait Part { def text: String override def toString = text } class Text(val text: String) extends Part {} class Parens(val contents: Seq[Part]) extends Part { val text = "(" + contents.mkString + ")" def mapText(m: Map[Parens, Char]) = { val inside = contents.collect{ case p: Parens => m(p).toString case x => x.toString } "(" + inside.mkString + ")" } override def equals(a: Any) = a match { case p: Parens => text == p.text case _ => false } override def hashCode = text.hashCode } Now you need to parse into these things: def str2parens(s: String): (Parens, String) = { def fail = throw new Exception("Wait, you told me the input would be perfect.") if (s(0) != '(') fail def parts(s: String, found: Seq[Part] = Vector.empty): (Seq[Part], String) = { if (s(0)==')') (found,s) else if (s(0)=='(') { val (p,s2) = str2parens(s) parts(s2, found :+ p) } else { val (tx,s2) = s.span(c => c != '(' && c != ')') parts(s2, found :+ new Text(tx)) } } val (inside, more) = parts(s.tail) if (more(0)!=')') fail (new Parens(inside), more.tail) } Now we've got the whole thing parsed. So let's find all the bits. def findParens(p: Parens): Set[Parens] = { val inside = p.contents.collect{ case q: Parens => findParens(q) } inside.foldLeft(Set(p)){_ | _} } Now we can build the map you want. def mapParentheses(s: String) = { val (p,_) = str2parens(s) val pmap = findParens(p).toSeq.sortBy(_.text.length).zipWithIndex.toMap val p2c = pmap.mapValues(i => ('a'+i).toChar) p2c.map{ case(p,c) => (p.mapText(p2c), c) }.toMap } Evidence that it works: scala> val s = "((2((x+3)+6)))" s: java.lang.String = ((2((x+3)+6))) scala> val map = mapParentheses(s) map: scala.collection.immutable.Map[java.lang.String,Char] = Map((x+3) -> a, (a+6) -> b, (2b) -> c, (c) -> d) I will leave it as an exercise to the reader to figure out how it works, with the hint that recursion is a really powerful way to parse recursive structures.
def parse(s: String, c: Char = 'a', out: Map[Char, String] = Map() ): Option[Map[Char, String]] = """\([^\(\)]*\)""".r.findFirstIn(s) match { case Some(m) => parse(s.replace(m, c.toString), (c + 1).toChar , out + (c -> m)) case None if s.length == 1 => Some(out) case _ => None } This outputs an Option containing a Map if it parses, which is better than throwing an exception if it doesn't. I suspect you really wanted a map from Char to the String, so that's what this outputs. c and out are default parameters so you don't need to input them yourself. The regex just means "any number of characters that aren't parens, eclosed in parens" (the paren characters need to be escaped with "\"). findFirstIn finds the first match and returns an Option[String], which we can pattern match on, replacing that string with the relevant character. val s = "((2((x+3)+6)))" parse(s) //Some(Map(a -> (x+3), b -> (a+6), c -> (2b), d -> (c))) parse("(a(aa))(a)") //None
SQLite3 haskell createFunction example
Here's the SQLite3 Haskell bindings with the ability to create function: http://hackage.haskell.org/packages/archive/sqlite/0.5.1/doc/html/Database-SQLite.html But I can't get to use this feature, I wrote the code like this: increment a = a + 1 checkout = do handle <- openConnection "test.db" ok <- createFunction handle "woot" (IsFunctionHandler increment) return $ execStatement handle "SELECT woot(5)"; But it isn't compile with "Not in scope: data constructor `IsFunctionHandler'" error The correct code is: module Test where import Database.SQLite import Int increment :: Int64 -> Int64 increment a = a + 1 checkout :: IO (Either String [[Row Value]]) checkout = do handle <- openConnection "test.db" ok <- createFunction handle "woot" increment execStatement handle "SELECT woot(5), woot(7), woot(128)" Thanks to HaskellElephant
IsFunctionHandler is a class, not a data constructor. It has several instances so if increment is an instance of IsFunctionHandler, wich it in this case is, you should be able to write: createFunction handle "woot" increment
F#: I cannot return unit in a do clause and still have side effects
I'm writing a simple ini file parser and I'm having a little problem with the initialization of the object in the "do" clause. It wants me to return a unit but i can't get the blankity function to do the side effects if I try to pipe into an "ignore" or if i return "()" directly. This code works as a separate function because I can ignore the results. #light module Utilities.Config open System open System.IO open System.Text.RegularExpressions open System.Collections.Generic type Config(?fileName : string) = let fileName = defaultArg fileName #"C:\path\myConfigs.ini" static let defaultSettings = dict[ "Setting1", "1"; "Setting2", "2"; "Debug", "0"; "State", "Disarray";] let settingRegex = new Regex(#"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))") let fileSettings = new Dictionary<string, string>() let addFileSetting (groups : GroupCollection) = fileSettings.Add(groups.Item("key").Value, groups.Item("value").Value) do File.ReadAllLines(fileName) |> Seq.map(fun line -> settingRegex.Match(line)) |> Seq.filter(fun mtch -> mtch.Success) |> Seq.map(fun mtch -> addFileSetting(mtch.Groups) // Does not have the correct return type //|> ignore //#1 Does not init the dictionary //() //#2 Does not init the dictionary //The extra step will work member c.ReadFile = File.ReadAllLines(fileName) |> Seq.map(fun line -> settingRegex.Match(line)) |> Seq.filter(fun mtch -> mtch.Success) |> Seq.map(fun mtch -> addFileSetting(mtch.Groups))
Use Seq.iter (executing an action for each element - returning unit) instead of Seq.map (transforming elements). The code doesn't work with ignore because Seq's are evaluated lazily and when you ignore the result, there is no need to run any code at all. Read this article