I'm converting a Ruby project to Elixir. How does Ruby's until loop translate to Elixir?
until scanner.eos? do
tokens << scan(line + 1)
end
Here's the full Ruby method:
def tokenize
#tokens = []
#lines.each_with_index do |text, line|
#scanner = StringScanner.new(text)
until #scanner.eos? do
#tokens << scan(line + 1)
end
end
#tokens
end
#lines is just a text file split by new lines. #lines = text.split("\n")
In Elixir, I've already converted the string scanner which looks like this: StringScanner.eos?(scanner):
#spec eos?(pid) :: boolean
def eos?(pid) when is_pid(pid) do
Also, in Elixir, tokens are tuples: #type token :: {:atom, any, {integer, integer}}. Where the {integer, integer} tuple is the line and position of the token.
This is the Elixir psuedo-code which doesn't quite work.
#spec scan(String.t, integer) :: token
def scan(text, line) when is_binary(text) and is_integer(line) do
string_scanner = StringScanner.new(text)
until StringScanner.eos?(string_scanner) do
result = Enum.find_value(#scanner_tokenizers, fn {scanner, tokenizer} ->
match = scanner.(string_scanner)
if match do
tokenizer.(string_scanner, match, line)
end
end)
IO.inspect result
end
StringScanner.stop(string_scanner)
result
end
Someone on the slack channel suggested using recursion, however they didn't elaborate with an example. I've seen recursion examples for summing / reducing which use accumulators etc. However, I don't see how that applies when evaluating a boolean.
Can anyone provide a working example which uses StringScanner.eos?(scanner)? Thanks.
It may be something like
def tokens(scanner) do
tokens(scanner, [])
end
defp tokens(scanner, acc) do
if StringScanner.eos?(scanner) do
acc
else
tokens(scanner, add_to_acc(scan_stuff(), acc))
end
end
At least this can be the general idea. As you'll see I kept a couple of functions very generic (scan_stuff/0 and add_to_acc/2) as I don't know how you mean to implement those; the first one is meant to do what scan(line + 1) does in the Ruby code, while the second one is meant to do what << does in the Ruby code (e.g., it could add the scanned stuff to the list of tokens or something similar).
Related
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.
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.
I'm studying functional programming and I want to implement something like this.
while(true) do
if(somethingHappensHere) {
break
}
counter++
end
return counter
How can I do this in functional way using elixir?
Thanks for this.
While in most functional programming languages one would use a recursion for this task, Elixir particularly provides the way to do this without using an explicit recursion call: Enum.reduce_while/3:
Enum.reduce_while(1..100, 0, fn i, acc ->
if condition, do: {:halt, acc}, else: {:cont, acc + i}
end)
For lazy evaluation one would use Stream.reduce_while/3.
To make it infinite, one might use one of infinite generators, provided by Stream module, like Stream.iterate/2:
Stream.iterate(0, &(&1+1)) |> Enum.reduce_while(0, fn i, acc ->
if i > 6, do: {:halt, acc}, else: {:cont, acc + 1}
end)
#⇒ 7
For the sake of recursion, this is how the recursive solution might be implemented in Elixir:
defmodule M do
def checker, do: & &1 <= 0
def factorial(v, acc \\ 1) do
if checker().(v), do: acc, else: factorial(v - 1, v * acc)
end
end
M.factorial 6
#⇒ 720
Not sure about elixir specifically, but you can achieve this using recursion:
function myFunction(int counter)
{
if (condition) {
return counter
}
return myFunction(counter + 1)
}
This essentially sets up a function that can infinitely recurse (call itself), each time passing in the next counter value.
By having the recursive call as the last thing the function does, this is known as tail-call recursion which elixir supports (as per: Does Elixir infinite recursion ever overflow the stack?)
This can then be used as such:
int counterValue = myFunction(0)
With the function only returning once the condition is true.
You could also make this more generic by having the function take another function that returns true or false (i.e. performs the conditional check).
As I said, unfortunately I'm not aware of the syntax of elixir, but I'm sure you'll be able to bridge that gap.
An example of something in Elixir syntax:
defmodule SOQuestion do
def test(counter) do
if (something_happens_here?()), do: counter, else: test(counter+1)
end
def something_happens_here?() do
true
end
end
And it would be invoked like this:
SOQuestion.test(0)
A couple of notes on this:
1.) It's a code fragment. Obviously it's tough to be very complete given the broad nature of your question.
2.) something_happens_here? being a predicate it would normally be named ending with a question mark.
3.) If something_happens_here? were defined in a different module, then the call would be if (Module.something_happens_here?())
4.) I've obviously coded something_happens_here? to simply return true unconditionally. In real code, of course, you'd want to pass some argument to something_happens_here? and act on that to determine which boolean to return.
Given all that I totally agree with #mudasowba--this sort of thing is usually better handled with one of the higher order functions built into the language. It's less error prone and often much easier for others to read too.
As mentioned, you could use a number of built-in functions like Enum.reduce_while/3. However, sometimes it is just as easy (or fun) to use simple recursion.
Using recursion:
I will make some generic examples and use bar(foo) as an example of your somethingHappensHere condition.
1) If bar(foo) is something allowed in a guard clause:
defmodule Counter do
def count do
count(foo, 0)
end
defp count(foo, count) when bar(foo), do: count
defp count(foo, count), do: count(foo, count + 1)
end
2) If bar(foo) is a function that returns a boolean:
defmodule Counter do
def count(foo) do
count(foo, 0)
end
defp count(foo, count) do
if bar(foo) do
count
else
count(foo, count + 1)
end
end
end
3) If bar(foo) returns something other than a boolean, that you can pattern-match on, like:
defmodule Counter do
def count(foo) do
count(foo, 0)
end
defp count(foo, count) do
case bar(foo) do
{:ok, baz} -> count
{:error, _} -> count(foo, count + 1)
end
end
end
Call the module and function:
Counter.count(foo)
I was wondering how I would work with hex strings in Elixir. Specifically, I'm interested in converting from Hex to ASCII.
In Ruby, an implementation of this may be:
["001C7F616A8B002128C1A33E8100"].pack('H*').gsub(/[^[:print:]]/, '.')
How would I accomplish this task with Elixir? I have tried:
<<00, 01, C7, F6...>>
but this isn't a correct representation of the hex for a string. Thanks for your time and assistance!
So I've made some progress but am currently struggling with the recursion aspect of this.
This is my solution thus far:
defmodule ElixirNetworkTools do
def decode(payload) do
upper_payload = String.upcase payload
case Base.decode16(upper_payload) do
:error -> decode_with_nonprintable_characters(payload)
{:ok, decoded_payload} -> decoded_payload
end
|> IO.write
end
def decode_with_nonprintable_characters(payload) do
String.chunk(payload, ~r/\w{2}/)
|> Enum.each(fn(byte) ->
case Base.decode16(byte) do
:error -> '.'
{:ok, decoded_payload} -> decoded_payload
end
end)
end
end
Here is another solution to the problem. A couple things before we start:
You can pass case: :mixed to Base.decode16/2: Base.decode16(string, case: :mixed), for this reason, you don't need do upcase before.
If you are going to raise on an invalid string, don't bother checking, just call decode16 directly as it also checks the size.
This means we can start with:
decoded = Base.decode16!(string, case: :mixed)
Now you need to replace non-printable characters. Don't use String.printable?/1 because it is about UTF-8 and not ASCII. We need to implement our own function but what makes more sense: to raise or replace them? It seems it must be considered an error if someone send invalidate data? If that is the case:
def validate_ascii!(<<h, t::binary>>) when h <= 127 do
validate_ascii!(t)
end
def validate_ascii!(<<>>) do
true
end
def validate_ascii!(rest) do
raise "invalid ascii on string starting at: #{rest}"
end
Alternatively you can just remove the last clause and it fail too.
Now we can put it together:
decoded = Base.decode16!(string, case: :mixed)
validate_ascii!(decoded)
decoded
EDIT: If you need to replace non-ascii by dots:
def keep_ascii(<<h, t::binary>>, acc) when h <= 127 do
keep_ascii(t, acc <> <<h>>)
end
def keep_ascii(<<_, t::binary>>, acc) do
keep_ascii(t, acc <> ".")
end
def keep_ascii(<<>>, acc) do
acc
end
The solution ended up being as follows, though if there is a cleaner or better solution I would be very interested in knowing it.
defmodule ElixirNetworkTools do
#doc """
The decode function takes a hexadecimal payload, such as one generated
by Snort, and returns the ASCII representation of the string.
## Example
iex> ElixirNetworkTools.decode("436F6E74656E742D4C656E6774683A203132")
{:ok, "Content-Length: 12"}
"""
def decode(payload) do
case _validate_length_of_snort(payload) do
:error -> raise "Invalid length hex string. Must be even length. Exiting"
_ -> nil
end
decoded = String.upcase(payload)
|> _do_decode
|> to_string
{:ok, decoded}
end
#doc """
Internal function used to manually process the hexadecimal payload,
and builds a char list of the printable characters. If a character is
not printable, we instead use periods.
## Example
iex> ElixirNetworkTools._do_decode("436F6E74656E742D4C656E6774683A203132")
["Content-Length: 12"]
"""
def _do_decode(payload) do
Base.decode16!(payload)
|> String.chunk(:printable)
|> Enum.map(fn(chunk) ->
case String.printable? chunk do
true -> chunk
_ -> "."
end
end)
end
#doc """
Internal function used to validate the length of the hexadecimal payload.
Hexadecimal strings should have an even number of characters.
## Example
iex> ElixirNetworkTools._validate_length_of_snort("436F6E74656E742D4C656E6774683A203132")
:ok
"""
def _validate_length_of_snort(payload) do
String.length(payload)
|> rem(2)
|> case do
0 -> :ok
_ -> :error
end
end
end
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.