function taking a Union with "failed"

20 views
Skip to first unread message

Martin R

unread,
Apr 12, 2026, 6:53:45 PM (4 days ago) Apr 12
to FriCAS - computer algebra system
Dear all!

I am trying to define a function taking an argument of type Union(SomeType, "failed"), and fail badly:

(1) -> U ==> Union(INT, "failed")
                                                                   Type: Void
(2) -> f(a:U): SEX == (a case INT => return (a::SEX); a case "failed" => return ("failed"::SEX))
   Function declaration f : Union(Integer,"failed") -> SExpression has
      been added to workspace.
                                                                   Type: Void
(3) -> x := "failed"::U

   (3)  "failed"
                                                    Type: Union("failed",...)
(4) -> f(x)
   Compiling function f with type Union(Integer,"failed") ->
      SExpression
 
   >> System error:
   The value
  "failed"
is not of type
  LIST

(4) -> f("failed")

   (4)  "failed"
                                                            Type: SExpression
(5) -> f(5)

   (5)  5
                                                            Type: SExpression
(6) -> f("failed"::U)
 
   >> System error:
   The function BOOT::|*1;f;2;frame1| is undefined.

What am I doing wrong?

Best wishes,

Martin

Waldek Hebisch

unread,
Apr 12, 2026, 11:29:57 PM (4 days ago) Apr 12
to 'Martin R' via FriCAS - computer algebra system
This is a bug. Fix is pretty simple, but before commiting it I want to
check if something related needs fixing.


--- ../trunk.pp6/src/interp/i-funsel.boot 2026-03-29 15:01:08.124682080 +0000
+++ i-funsel.boot 2026-04-13 03:17:36.192337540 +0000
@@ -765,6 +765,7 @@
-- in the domain of computation dc
-- tar may be NIL (= unknown)
null isLegitimateMode(tar, nil, nil) => nil
+ STRINGP(dc) => nil
dcName := first dc
member(dcName,'(Union Record Mapping Enumeration)) =>
-- First cut code that ignores args2, $Coerce and $SubDom
--
Waldek Hebisch

Ralf Hemmecke

unread,
Apr 13, 2026, 12:58:09 AM (4 days ago) Apr 13
to fricas...@googlegroups.com
On 4/13/26 05:29, Waldek Hebisch wrote:
>> (2) -> f(a:U): SEX == (a case INT => return (a::SEX); a case "failed" =>
>> return ("failed"::SEX))

>> What am I doing wrong?

> This is a bug. Fix is pretty simple, but before commiting it I want to
> check if something related needs fixing.

OK. However, formally, I would have said that the following would be a
better definition.

f(a:U): SEX == (a case INT => a::SEX; "failed"::SEX)

Martin's function definition potentially can return Void (if both cases
return false). Does the interpreter really not care about type
specifications for the return type? Or does the interpreter **know**
that there can only be two cases and Void is never returned?

Ralf

Martin R

unread,
Apr 13, 2026, 3:18:38 AM (4 days ago) Apr 13
to FriCAS - computer algebra system
Ah, what's the specification of "return"?

Ralf Hemmecke

unread,
Apr 13, 2026, 3:31:28 AM (4 days ago) Apr 13
to fricas...@googlegroups.com
> Ah, what's the specification of "return"?

Oh, that was not my point.

However,

(cond => X) is essentially (if cond then X)
(cond => X; Y) is essentially (if cond then X else Y)

In the first case, it is not clear what the type of the return value is
if cond is false.

You need "return" in cases like

foo(...): INT ==
for i in 1..10 repeat
prime?(i) => return i
print i
-1

Without "return" that function would always give -1, because "=>" ends
the block (= body of the loop), but not the whole loop.
Additionally it will print i for the **all** i in 1..10 for which
cond?(i) is false.

%%% (154) -> foo():INT ==(for i in 1..10 repeat (prime? i => i; print
i); -1)
Function declaration foo : () -> Integer has been added to
workspace.
%%% (155) -> foo()
Compiling function foo with type () -> Integer
1
4
6
8
9
10

(155) - 1

Ralf

Martin R

unread,
Apr 13, 2026, 3:41:32 AM (4 days ago) Apr 13
to FriCAS - computer algebra system
Ah, perfect!  (yes, I understood your true point, but I was confused about return)

Waldek Hebisch

unread,
Apr 13, 2026, 7:18:12 AM (4 days ago) Apr 13
to 'Ralf Hemmecke' via FriCAS - computer algebra system
When in doubt interpreter inserts appropriate coercion. So in
this case interpreter adds coercion from Void to SXepression.
This coercion, if executed probably would fail at runtime.
It probably would be clearer to write:

f(a:U): SEX ==
a case INT => return (a::SEX)
a case "failed" => return ("failed"::SEX)
error "impossible"

It does not matter in this case, as error happened in interpreter
code, before execution of 'f'.

You can see generated code doing:

)boot $reportOptimization := true

Martin's version is correct, it just generates suboptimal code
(Spad compiler should do much better on such code).

--
Waldek Hebisch

Martin R

unread,
Apr 13, 2026, 9:30:32 AM (4 days ago) Apr 13
to FriCAS - computer algebra system
Here is another surprise:

(1) -> U ==> Union(INT, "failed")
                                                                   Type: Void
(2) -> f(obj) == (obj case Integer => 1; obj case "failed" => 0)
                                                                   Type: Void
(3) -> f(1::U)
 
   case is only used for Unions and the object on the left-hand side
      does not belong to a union.

Martin

Kurt Pagani

unread,
Apr 13, 2026, 9:48:04 AM (4 days ago) Apr 13
to 'Martin R' via FriCAS - computer algebra system

I'm not really surprised :)
The interpreter is not a 100% clairvoyant.
Why not use

U ==> Union(INT, "failed")
V ==> Union(U,INT)

f(obj:U):V == (obj case Integer => return 1; obj case "failed" => return 0)
> --
> You received this message because you are subscribed to the Google
> Groups "FriCAS - computer algebra system" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to fricas-devel...@googlegroups.com <mailto:fricas-
> devel+un...@googlegroups.com>.
> To view this discussion visit https://groups.google.com/d/msgid/fricas-
> devel/65d8d799-2389-41e0-9f7b-da02863db295n%40googlegroups.com <https://
> groups.google.com/d/msgid/fricas-devel/65d8d799-2389-41e0-9f7b-
> da02863db295n%40googlegroups.com?utm_medium=email&utm_source=footer>.

Kurt Pagani

unread,
Apr 13, 2026, 10:19:16 AM (4 days ago) Apr 13
to fricas...@googlegroups.com
You're right, after all *it's a surprise*.


q:=1::U
if q case Integer then 1 else if q case "failed" then 0 --> 1
q:="failed"::U
if q case Integer then 1 else if q case "failed" then 0 --> 0

f(obj) ==
if obj case Integer
then 1
else if obj case failed then 0


h:=x+-> if x case Integer then 1 else if x case "failed" then 0
h

x
+->
if x case Integer
then 1
else if x case failed then 0

Waldek Hebisch

unread,
Apr 13, 2026, 4:36:50 PM (3 days ago) Apr 13
to 'Martin R' via FriCAS - computer algebra system
On Mon, Apr 13, 2026 at 06:30:32AM -0700, 'Martin R' via FriCAS - computer algebra system wrote:
> Here is another surprise:
>
> (1) -> U ==> Union(INT, "failed")
> Type:
> Void
> (2) -> f(obj) == (obj case Integer => 1; obj case "failed" => 0)
> Type:
> Void
> (3) -> f(1::U)
>
> case is only used for Unions and the object on the left-hand side
> does not belong to a union.

This is not so surprising if you realize that when interpreting
(and not compiling) interpreter immediatly converts Union to
actual branch. So 'f' never sees Union, it gets one of two
possible types.

--
Waldek Hebisch

Martin R

unread,
Apr 13, 2026, 5:29:33 PM (3 days ago) Apr 13
to FriCAS - computer algebra system
Ah, many thanks!
Reply all
Reply to author
Forward
0 new messages