PureScript - fromMaybe does not return the Maybe value - purescript

Consider the following simple code example,
module Main where
import Prelude (discard, Unit, ($))
import Effect (Effect)
import Effect.Console (log)
import Data.Int ( toStringAs, fromNumber, decimal )
import Data.Maybe ( fromMaybe )
myNumber :: Number
myNumber = 4.762
myInteger :: Int
myInteger = fromMaybe 0 (fromNumber myNumber)
main ∷ Effect Unit
main = do
log ( toStringAs decimal myInteger )
The expected value would be
4
However, the output of this code is
0
Question:
Why does fromMaybe return 0 instead of the maybe value (4) ?

Your problem is not with fromMaybe, but with fromNumber (btw, pro tip: when you see a problem, never assume you know what the cause is; if you have a hypothesis for the cause, check it first, only then try to fix).
Once again, read the docs. Quote:
The number must already be an integer and fall within the valid range of values for the Int type otherwise Nothing is returned.
Your number is not an integer, so fromNumber returns Nothing, just like it promised.
Judging by your expected output, what you probably actually want is floor.

Related

Purescript: Convert Maybe Type to Type

The following simple code converts an Integer value to a string value and logs it.
module Main where
import Effect (Effect)
import Effect.Console (log)
import Prelude ((<>), Unit, discard)
import Data.Int (toStringAs, radix)
type CustomerFeedback = {
customerServiceScore :: Int,
productQualityScore :: Int,
onTimeDeliveryScore :: Int
}
feedback :: CustomerFeedback
feedback = {
customerServiceScore : 4,
productQualityScore : 2,
onTimeDeliveryScore : 6
}
stringifyCustomerFeedback :: CustomerFeedback -> String
stringifyCustomerFeedback feedback = "Service: " <> toStringAs (radix 10) feedback.customerServiceScore
main ∷ Effect Unit
main = do
log (stringifyCustomerFeedback(feedback))
However, running this code produces the following error:
Could not match type
Maybe Radix
with type
Radix
while checking that type Maybe Radix
is at least as general as type Radix
while checking that expression radix 10
has type Radix
in value declaration stringifyCustomerFeedback
Questions would be as follows:
How do you change the code above so it outputs a string as expected and not an error?
What's the point of a Maybe Radix type if using it where you would use a Radix causes an error? How do you use a Maybe value?
The idea of the radix function is that you give it a number and it creates a Radix from it. But not every number constitutes a valid Radix. For example, if you give it -5, it shouldn't work. And neither should 0 or 1 for example. For some technical reasons, radices above 32 are also deemed invalid.
So that's why it returns Maybe: it would be Nothing in case the number you gave it wasn't a "valid" radix.
And the use case for that function is when you don't actually know the number ahead of time. Like if you get it from the user. Or from some sort of config file or whatnot. In that case, if you get a Nothing, you would interpret that as "invalid user input" or "corrupted config file" and report an error accordingly. And you won't even get as far as calling toStringAs. This is one of the big selling points of static types: applied properly, they can force you to write a correct, reliable program, without ignoring edge cases.
However, in case you already know that you're interested in decimal radix, just use decimal. It's a Maybe-free constant provided by the library, along with some other frequently used ones, such as binary and octal.
stringifyCustomerFeedback feedback = "Service: " <> toStringAs decimal feedback.customerServiceScore

Big Int in scala

I'm new to Scala. I'm trying to create a test case for a simple factorial function.
I couldn't assign the result value in the assert statement. I'm getting
Integer number is out of range even for type Long error in IntelliJ.
test("Factorial.factorial6") {
assert(Factorial.factorial(25) == 15511210043330985984000000L)
}
I also tried to assign the value to val, using the 'L' literal, again it shows the same
message.
val b: BigInt = 15511210043330985984000000L
I'm clearly missing some basic stuff about Scala, I would appreciate your help, to solve this
The value you are giving is indeed larger than can be held in a Long, and that is the maximum size for a literal value in Scala. However you can initialise a BigInt using a String containing the value:
val b = BigInt("15511210043330985984000000")
and therefore
assert(Factorial.factorial(25) == BigInt("15511210043330985984000000"))

How to match and delete an element from a queue?

According to 1800-2012 specs,
Queue::delete( [input int index] )
deletes an element of a queue in SystemVerilog, furthermore, a Queue can perform the same operations as an unpacked Array, giving it access to:
Array::find_first_index( )
which returns the index of the first element matching a certain criteria. i.e.
find_first_index( x ) with ( x == 3)
Now I'd like to delete a unique item, guaranteed to exist, from the Queue. Combining 1 and 1 gives me:
queue.delete(queue.find_first_index( x ) with ( x == obj_to_del ));
The compiler does not appreciate that though saying that the argument passed must be either an integer or integer compatible. I could probably pull the two apart:
int index = queue.find_first_index( x ) with ( x == obj_to_del );
queue.delete( index );
or force an integer by typecasting find_first_index:
queue.delete(int'(queue.find_first_index( x ) with ( x == obj_to_del ))) //Just finished compiling, does not work.
The former does not look very elegant to me, and the latter seems somewhat forced which made me curious if there is maybe a more proper way to accomplish this. Is find_first_index possibly returning an array of size one with the index at location 0?
EDIT: I foolishly did not provide a self contained example: A stripped example of what I'm doing looks like:
class parent_task;
endclass;
class child_taskA extends parent_task;
endclass;
class child_taskB extends parent_task;
endclass;
class task_collector;
child_taskA A_queue[$];
child_taskB B_queue[$];
function delete_from_queue(parent_task task_to_del);
case (task_to_del.type):
A: A_queue.delete(A_queue.find_first_index( x ) with ( x == task_to_del));
B: B_queue.delete(B_queue.find_first_index( x ) with ( x == task_to_del));
default: $display("This shouldn't happen.");
endfunction
endclass
The error message, word for word is:
Error-[SV-IQDA] Invalid Queue delete argument
"this.A_queue.find_first_index( iterator ) with ((iterator == task))"
Queue method delete can take optional integer argument. So, argument passed
to it must be either integer or integer assignment compatible.
There are checks in place to make sure that the task in question exists before the call to delete_from_queue.
The int cast didn't work for me as well but the following worked
int index_to_del[$];
index_to_del = que.find_first_index(x) with ( x == task_to_del );
que.delete(index_to_del[0]);
queue.delete(int'(queue.find_first_index( x ) with ( x == obj_to_del )));
works for me. It would really help if you could provide complete self contained examples like the one below:
module top;
int queue[$] = {1,2,3,4,5};
let object_to_del = 3;
initial begin
queue.delete(int'(queue.find_first_index( x ) with ( x == object_to_del )));
$display("%p", queue);
end
endmodule
But what if there was no match? Would you not need to test the result from find_first_index() anyways before deleting?

How does PyNumber_Float handle an argument that is already a float?

Documentation for PyNumber_Float (here) doesn't specify what happens if you pass in a PyObject* that points to another float.
e.g.
PyObject* l = PyLong_FromLong( 101 );
PyObject* outA = PyNumber_Float(l);
outA will point to a newly created float PyObject
(or if there already exists one with that value, I think it will point to that and just increment the reference counter)
However,
PyObject* f = PyFloat_FromDouble( 1.1 );
PyObject* outB = PyNumber_Float(f);
What happens here?
Does it simply return the same pointer?
Does it first increment the reference count and then return the same pointer?
Or does it return a pointer to a new PyObject?
Is the behaviour guaranteed to be identical for the equivalent C-API calls for generating other primitives, such as Long, String, List, Dict, etc?
Finally, should the documentation clarify this situation? Would it be reasonable to file a doc-bug?
Thanks to haypo on the dev IRC channel, the following test shows that it returns the same object, with the reference counter incremented:
>>> x=1.1
>>> y=float(x)
>>> y is x, sys.getrefcount(x)-1, sys.getrefcount(y)-1
(True, 2, 2)
>>> y+=1
>>> y is x, sys.getrefcount(x)-1, sys.getrefcount(y)-1
(False, 1, 1)
Note: explanation of why refcount is one-too-high here
Note: x is y compares the memory address, "x is y" is the same as "id(x) == id(y)"
Of course it is possible that some assignment-operator optimisation is bypassing the application of float()

How to return a value from a Python callback in Fortran using F2Py

Consider the following Fortran subroutine, defined in test.f:
subroutine test(py_func)
use iso_fortran_env, only stdout => output_unit
external py_func
integer :: a
integer :: b
a = 12
write(stdout, *) a
b = py_func(a)
write(stdout, *) b
end subroutine
Also the following Python code, defined in call_test.py:
import test
def func(x):
return x * 2
test.test(func)
Compiled with the following (Intel compiler):
python f2py.py -c test.f --fcompiler=intelvem -m test
I expect this as output when I run test:
12
24
But I actually get this:
12
0
It seems as if b is being initialised with a default value instead of the result of test. I have tried using the following in the Fortran:
!f2py intent(callback) py_func
external py_func
!f2py integer y,x
!f2py y = py_func(x)
But my program crashes after the printout of 12 to the console.
Any ideas what could be going on here? The reason for the crash would be a bonus, but I'm really just interested in getting a simple callback working at this point.
I don't claim to understand it, I found the answer on an F2Py forum thread. Adding integer py_func (not prefixed by !f2py) does the trick for me:
subroutine test(py_func)
use iso_fortran_env, only stdout => output_unit
!f2py intent(callback) py_func
external py_func
integer py_func
!f2py integer y,x
!f2py y = py_func(x)
integer :: a
integer :: b
a = 12
write(stdout, *) a
b = py_func(a)
write(stdout, *) b
end subroutine
Perhaps this is to do with space being needed for a temporary value used to store the result before being assigned to b? In any case, it is apparently compiler-dependent, which explains why it is not in various F2Py callback examples you can find elsewhere online.