I wrote a program that will determine whether some imaginary school would have a snow day or not. I have the program working correctly I'm just having an issue.
Basically what I want is for the True/False to be Y/N. And later when I print SnowDay --tells whether there's a snow day. Then it will print either "Yes" or "No" instead of "True" or "False"
SofieAssignment : Boolean;
SnowDay : Boolean;
.
.
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
Get(Item => SophieAssignment);
.
.
Put(Item => "Should we have a snow day today? " & Boolean'Image (SnowDay));
Assuming I understand what you're trying to do:
(1) If you want the user to enter Y or N for SophieAssignment, there are a couple possibilities:
You can input a string and analyze the string yourself.
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
declare
Answer : String := Get_Line; -- Get_Line is in Ada.Text_IO
begin
if Answer = "Y" or else Answer = "y" or else Answer = "Yes" or else
Answer = "yes" then
SophieAssignment := True;
elsif Answer = "N" or else Answer = "n" or else Answer = "No" or else
Answer = "no" then
SophieAssignment := False;
else
-- whatever you want to do for an invalid entry
end if;
end;
(This could be improved, but I'm just trying to cover the fundamental approach.) Another possibility is to define your own enumeration that has the values Y and N:
type Yes_No is (N, Y);
package Yes_No_IO is new Enumeration_IO (Yes_No); -- Enumeration_IO is in Ada.Text_IO
Answer : Yes_No;
Put(Item => "Does Sophie have a big assignment due in class, True/False? ");
Yes_No_IO.Get(Item => Answer);
SophieAssignment := (Answer = Y);
Get here will set Answer to either Y or N if the user enters the enumeration name (in either case); it will raise Data_Error if something else is entered. I'd prefer the first method if you want better control over how input is handled. For the second, if the user enters "Y Z", Get will return the Y, and the Z is left in the input stream waiting for the next input operation. Also, the first method allows for multiple possible answers better than the second, although you could make it work with an enumeration like
type Yes_No is (N, No, Y, Yes);
(2) To output "Yes" or "No" based on a Boolean, you can use a function as in Keith's answer, or you can set up an array:
type Const_String_Acc is access constant String;
Yes_No_Image : constant array (Boolean) of Const_String_Acc :=
(False => new String' ("No"),
True => new String' ("Yes"));
Put(Item => "Should we have a snow day today? " & Yes_No_Image (SnowDay).all);
To print a Boolean value as "Yes" or "No", just write a function:
function Boolean_Image(B: Boolean) return String is
begin
if B then
return "Yes";
else
return "No";
end if;
end Boolean_Image;
and use it in place of Boolean'Image.
To read a value from the user as Y or y for True, or as N or n for False, just read a Character value and test it to determine which Boolean value to set. Think about how you want to respond if the character the user enters is not any of Y, y, N, or n. You can use Get_Immediate to read a single character without waiting for a newline on input.
type Snow_Day_Type is new Boolean;
function Yes return Snow_Day_Type is (Snow_Day_Type'(True));
function No return Snow_Day_Type is (Snow_Day_Type'(False));
Related
Suppose I'm using a package function f that takes a single argument x and performs some error checking on that argument. Like, is x of the right type? Etc. And if there is an error then f(x) throws an error with Error().
Is there an easy way to write a wrapper function fCatch around f to catch that error, and say return false if f(x) throws an error but true otherwise? The naïve way to accomplish this same effect would be to copy the code for f and change all the Error(...); lines into a return false; and set a return true; at the end, but it's bad form to duplicate all the error-checking code.
As per Alexander Konovalov's comment, the following works, except the Error(...) message that f(x) triggers still prints.
fCatch := function(x)
local result;
BreakOnError := false;
result := CALL_WITH_CATCH(f, [ x ])[1];;
BreakOnError := true;
return result;
end;
A warning: the CALL_WITH_CATCH function, and any other function with an ALL CAPS name, is undocumented and intended to only be used internally in GAP.
What shoud I do to execute some code (ie: MsgBox "Hello") by:
Pressing win+m
Unpressing m whithout unpressing win
Pressing p
Seems like there's a good answer already, I just wanted to input what I could think of, so here's a version of the earlier answer, but without Sends.
I'd say a solution without them is always desirable, though, of course, in something as small as this, you'll struggle to find any difference in practice.
;runs after m is released on a LWin+m press
<#m up::
Hotkey, <#p, WinMP_Callback, On ;Enable LWin+p hotkey
KeyWait, LWin ;wait for LWin to be released
if (A_PriorKey = "m")
WinMinimizeAll ;keep win+m functional
Hotkey, <#p, , Off ;disable LWin+p hotkey
return
WinMP_Callback()
{
;do stuff
;add this at the end if you dont want
;to be able to keep running this function
;on subsequent presses of p before LWin is released
;Hotkey, <#p, , Off
}
So pretty much what the difference here is toggling the LWin+p hotkey on and off and just using WinMinimizeAll instead of sending LWin+m, since they're the same thing.
Try this:
<#m:: ; "<#" means "LWin"
LWin_m := true ; assign the Boolean value "true" or "1" to this variable
KeyWait, LWin, L ; wait for LWin to be released
LWin_m := false
return
<#p::
If (LWin_m) ; If this variable has the value "true"
msgbox "Hello"
; else
; do sth else
return
EDIT:
For not losing normal win+m and win+p try this:
<#m:: ; "<#" means "LWin"
LWin_m := true ; assign the Boolean value "true" or "1" to this variable
KeyWait, LWin, L ; wait for LWin to be released
If (A_PriorKey = "m")
Send #m
LWin_m := false
return
<#p::
If (LWin_m) ; If this variable has the value "true"
msgbox "Hello"
else
Send #p
return
In a for loop, a different variable is assigned a value. The variable which has already been assigned a value is getting assigned the value from next iteration. At the end, both variable have the same value.
The code is for validating data in a file. When I print the values, it prints correct value for first iteration but in the next iteration, the value assigned in first iteration is changed.
When I print the value of $value3 and $value4 in the for loop, it shows null for $value4 and some value for $value3 but in the next iteration, the value of $value3 is overwritten by the value of $value4
I have tried on rakudo perl 6.c
my $fh= $!FileName.IO.open;
my $fileObject = FileValidation.new( file => $fh );
for (3,4).list {
put "Iteration: ", $_;
if ($_ == 4) {
$value4 := $fileObject.FileValidationFunction(%.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
}
if ($_ == 3) {
$value3 := $fileObject.FileValidationFunction(%.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
}
$fh.seek: SeekFromBeginning;
}
TL;DR It's not possible to confidently answer your question as it stands. This is a nanswer -- an answer in the sense I'm writing it as one but also quite possibly not an answer in the sense of helping you fix your problem.
Is it is rw? A first look.
The is rw trait on a routine or class attribute means it returns a container that contains a value rather than just returning a value.
If you then alias that container then you can get the behavior you've described.
For example:
my $foo;
sub bar is rw { $foo = rand }
my ($value3, $value4);
$value3 := bar;
.say for $value3, $value4;
$value4 := bar;
.say for $value3, $value4;
displays:
0.14168492246366005
(Any)
0.31843665763839857
0.31843665763839857
This isn't a bug in the language or compiler. It's just P6 code doing what it's supposed to do.
A longer version of the same thing
Perhaps the above is so far from your code it's disorienting. So here's the same thing wrapped in something like the code you provided.
spurt 'junk', 'junk';
class FileValidation {
has $.file;
has $!foo;
method FileValidationFunction ($,$) is rw { $!foo = rand }
}
class bar {
has $!FileName = 'junk';
has %.ValidationRules =
{ 3 => { ValidationFunction => {;}, Arguments => () },
4 => { ValidationFunction => {;}, Arguments => () } }
my ($value3, $value4);
method baz {
my $fh= $!FileName.IO.open;
my $fileObject = FileValidation.new( file => $fh );
my ($value3, $value4);
for (3,4).list {
put "Iteration: ", $_;
if ($_ == 4) {
$value4 := $fileObject.FileValidationFunction(
%.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
}
if ($_ == 3) {
$value3 := $fileObject.FileValidationFunction(
%.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
}
$fh.seek: SeekFromBeginning;
.say for $value3, $value4
}
}
}
bar.new.baz
This outputs:
Iteration: 3
0.5779679442816953
(Any)
Iteration: 4
0.8650280000277686
0.8650280000277686
Is it is rw? A second look.
Brad and I came up with essentially the same answer (at the same time; I was a minute ahead of Brad but who's counting? I mean besides me? :)) but Brad nicely nails the fix:
One way to avoid aliasing a container is to just use =.
(This is no doubt also why #ElizabethMattijsen++ asked about trying = instead of :=.)
You've commented that changing from := to = made no difference.
But presumably you didn't change from := to = throughout your entire codebase but rather just (the equivalent of) the two in the code you've shared.
So perhaps the problem can still be fixed by switching from := to =, but in some of your code elsewhere. (That said, don't just globally replace := with =. Instead, make sure you understand their difference and then change them as appropriate. You've got a test suite, right? ;))
How to move forward if you're still stuck
Right now your question has received several upvotes and no downvotes and you've got two answers (that point to the same problem).
But maybe our answers aren't good enough.
If so...
The addition of the reddit comment, and trying = instead of :=, and trying the latest compiler, and commenting on those things, leaves me glad I didn't downvote your question, but I haven't upvoted it yet and there's a reason for that. It's because your question is still missing a Minimal Reproducible Example.
You responded to my suggestion about producing an MRE with:
The problem is that I am not able to replicate this in a simpler environment
I presumed that's your situation, but as you can imagine, that means we can't confidently replicate it at all. That may be the way you prefer to go for reasons but it goes against SO guidance (in the link above) and if the current answers aren't adequate then the sensible way forward is for you to do what it takes to share code that reproduces your problem.
If it's large, please don't just paste it into your question but instead link to it. Perhaps you can set it up on glot.io using the + button to use multiple files (up to 6 I think, plus there's a standard input too). If not, perhaps gist it via, say, gist.github.com, and if I can I'll set it up on glot.io for you.
What is probably happening is that you are returning a container rather than a value, then aliasing the container to a variable.
class Foo {
has $.a is rw;
}
my $o = Foo.new( a => 1 );
my $old := $o.a;
say $old; # 1
$o.a = 2;
say $old; # 2
One way to avoid aliasing a container is to just use =.
my $old = $o.a;
say $old; # 1
$o.a = 2;
say $old; # 1
You could also decontainerize the value using either .self or .<>
my $old := $o.a.<>;
say $old; # 1
$o.a = 2;
say $old; # 1
(Note that .<> above could be .self or just <>.)
I tried with, c::Char = read(stdin, Char);
It reads character(s) from keyboard only after hitting enter but not upon every keydown/release.
Please guide me in reading keyboard input upon key press or release!
Update 1:
function quit()
print("Press q to quit!");
opt = getc1();
while true
if opt = 'q'
break;
else
continue;
end
end
end
throws error:
TypeError:non-boolean(Int64) used in boolean context.
Please help me!
This is not that simple.
You can try this more low-level solution:
function getc1()
ret = ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, true)
ret == 0 || error("unable to switch to raw mode")
c = read(stdin, Char)
ccall(:jl_tty_set_mode, Int32, (Ptr{Cvoid},Int32), stdin.handle, false)
c
end
or this more higher level one:
function getc2()
t = REPL.TerminalMenus.terminal
REPL.TerminalMenus.enableRawMode(t) || error("unable to switch to raw mode")
c = Char(REPL.TerminalMenus.readKey(t.in_stream))
REPL.TerminalMenus.disableRawMode(t)
c
end
depending on what you need (or write yet another implementation using the ideas here). The key challenge is that "normal keys", like ASCII are always processed correctly. However, the solutions differ in the way how they handle characters like 'ą' (some character that is larger UNICODE) or UP_ARROW (when you press arrow up on the keyboard) - you here have to experiment and decide what you want (or maybe it is enough for you to read UInt8 values one by one and manually reconstruct what you want?).
EDIT
The problem is with your quit function. Here is how it should be defined:
function quit()
print("Press q to quit!");
while true
opt = getc1();
if opt == 'q'
break
else
continue
end
end
end
The following example may be helpful:
import REPL
function wait_for_key( ;
io_in::IO = stdin,
io_out::IO = stdout,
prompt::String = "press any key [d]raw [n]odraw [q]uit : ",
)
print(io_out, prompt)
t = REPL.TerminalMenus.terminal
REPL.Terminals.raw!(t, true)
char = read(io_in, Char)
REPL.Terminals.raw!(t, false)
write(io_out, char)
write(io_out, "\n")
return char
end
I am new to elixir, having hard time with updating the variables. Need some help. I have two Maps
firstMsg = %{msg: "Hello", vt: %{"p1" => 1, "p2" => 1, "p3" => 1}, from: "p3"}
state = %{ :name => "p2",
vector: %{"p1" => 0, "p2" => 0, "p3" => 0},
participants: ["p1","p3","p2"]
}
I am passing these two maps in a function, which should return me either true or false, depending on some conditions.
defmodule Testfunc do
def keep_in_pending(firstMsg, state) do
if (firstMsg.vt[firstMsg.from] == state.vector[firstMsg.from] + 1) do
#IO.puts("Origin proc clock is 1 step ahead from rcvd process Origin clk")
checking = false #initially set this to false
for n <- state.participants do
if n != firstMsg.from do #filter the origin processes
IO.puts("#{n}: #{inspect firstMsg.vt[n]} <= #{n}: #{inspect state.vector[n]} ")
checking = cond do
(firstMsg.vt[n] <= state.vector[n]) -> false
(firstMsg.vt[n] > state.vector[n]) -> true
end
end
end
end
checking
end
end
out = Testfunc.keep_in_pending(firstMsg, state)
IO.puts("#{inspect out}")
It always gives me false (value that I initially assigned to it), and doesn't updates. I think the scope of variable is restricted to the inner "if". Can anyone give me suggestion on how to re arrange this code so that it returns me proper updated boolean value ?
So in this case it should return me true because firstMsg.vt["p1"] > state.vector["p1"].
Welcome to Elixir. You're right, it is a matter of scope, but it runs a bit deeper than that. Elixir is a language where your data is immutable. You can't set checked to false, run a loop, and set it to true somewhere in that loop. That would mutate checked. It's not that someone designed devilish scope rules to prevent this, but rather that the underlying virtual machine doesn't mutate state.
The style of programming where you set some state, then run a procedure that changes that state, relies on mutable state. When state is immutable, the alternative to a loop is instead recursion. You carry new state in every recursive call.
You're learning a functional language, and I think it will be helpful to pull apart your code into a few functions. This will both address your immediate concern, and make your code easier to understand.
def keep_in_pending(%{from: from, vt: vt}, %{vector: vector, participants: ps}) do
if vt[from] == vector[from] + 1 do
ps
|> Enum.reject(& &1 == from)
|> check_participants(vector, vt, false)
end
end
def check_participants([], _, _, bool), do: bool
def check_participants([h | t], vector, vt, bool) do
check_participants(t, vector, vt, vt[h] > vector[h])
end
I'll briefly explain it.
First, note that I've pattern matched the inputs, to pull out the interesting parts we're using in the function body. This gets rid of some of the repetitive firstMsg.from business. (Btw, snake_case your variable names.)
Second, I haven't touched the gnarly outer if-condition. I simply don't know what it means. You should perhaps extract it and give it an intention revealing name.
The real action begins when we pipe participants. You were filtering inside your list comprehension. I've filtered with Enum.reject/1 instead. Then we pipe the list into a recursive function. It's going to carry the boolean through to the end, starting off with false. It needs to check values in vt and vector, so they're also passed in.
The first rule of recursion is the first rule of recursion. No, wait. It's to think about how to terminate the recursion. We're working through a list of participants, so we'll stop when the list is empty. At that point, we have the boolean we're looking for, so just return it.
The recursive step is to pick off an item from the list (h), use it to determine a new boolean (vt[h] > vector[h]) and call the function again with the rest of the list (check_participants(t, ...)).
Hope this helps! Have fun learning functional programming!
So here is an idea: if you are trying to make a function return a boolean, just make it return a boolean, don't assign it to a variable. Assigning inside an if/case/cond will show a warning. Also, you are not reassigning the checking because variables bound inside the comprehension (for) are restricted to that scope. Your best tools in Elixir will be first pattern matching and second the pipe operator, so always try to use them.
Here is an idea to refactor that code:
defmodule Testfunc do
def keep_in_pending(firstMsg, state) do
if (firstMsg.vt[firstMsg.from] == state.vector[firstMsg.from] + 1) do
state.participants
|> Enum.filter(fn (n) -> n != firstMsg.from end)
|> Enum.reduce(fn (n, _) ->
cond do
(firstMsg.vt[n] <= state.vector[n]) -> false
(firstMsg.vt[n] > state.vector[n]) -> true
end
end)
end
end
end