13
\$\begingroup\$

Inspired by this excellent challenge (from which the bulk of this text is blatantly duct-taped) – and my highschool philosophy project...

I define the following operators:

Fuzzy Conjunction a ×F b is a × b

Fuzzy Division a ÷F b is a ÷ b

Fuzzy NegationF b is 1 – b

Fuzzy Disjunction a +F b is –F ((–F a) ×S (–F b) which is equivalent to 1 – (1 – a) × (1 – b)

With all this in mind, create an interpreter that will evaluate infix expressions that use the following operators (i.e., a + b, not a b + or + a b). Alternatively, extend the language of your choice to include the notation.

×    Multiplication
÷    Division
–    Subtraction
+    Addition
×F   Fuzzy Conjunction
÷F   Fuzzy Division
–F   Fuzzy Negation
+F   Fuzzy Disjunction

Notice that a -F b is not defined. You may leave it undefined, or define it as you see fit.

You may substitute * for × and/or - for and/or / for ÷, (or use whatever single symbols your language uses for the four basic arithmetic operations) as long as you stay consistent: You may not use * and ×F together.

You may choose to require or prohibit spacing around tokens.

You may choose any of the following rules for order of precedence:

  1. As normal mathematics, and each Fuzzy operator has a higher order precedence than their normal counterpart.

  2. As normal mathematics, and each Fuzzy operator has a lower order precedence than their normal counterpart.

  3. As normal mathematics, and the Fuzzy operators all have higher order precedence than all the normal operators.

  4. As normal mathematics, and the Fuzzy operators all have lower order precedence than all the normal operators.

  5. Strict left-to-right.

  6. Strict right-to-left.

  7. Normal and Fuzzy operators have the same precedence and are evaluated left-to-right.

  8. Normal and Fuzzy operators have the same precedence and are evaluated right-to-left.

Leave a comment if you desire another precedence rule.

Test cases using precedence rule 6:

> 5 +F 10 + 3
-47     // 1 - (1 - 5) × (1 - 13)
> 10 × 2
20      // 2 × 10
> 10 ×F 1
10      // 1 × 10
> 23 × 3
69      // 23 × 3
> 123 ×F 2 × 3
738     // 123 × 2 × 3
> 5 + 3 +F 2
4       // 5 + 1 - (1 - 3) × (1 - 2)
> 150 ÷F 3
50      // 150 ÷ 3
> 150 ÷ 53
2.83    // 150 ÷ 53
> -F -F -F 0
1       // 1 - (1 - (1 - 0))
> -500
-500    // - 500
> -F 6 - 1
-4      // 1 - 5
> 12 +F 633 ×F 3
-20877  // 1 - (1 - 12) × (1- 633 × 3)

This is a , so the shortest program in bytes wins.

\$\endgroup\$
9
  • 5
    \$\begingroup\$ I'm trying this in Dyalog APL, and something feels wrong about using APL with regex. \$\endgroup\$ – lirtosiast Jan 5 '16 at 23:31
  • \$\begingroup\$ Does -M nest arbitrarily? That is, should our code handle -M -M -M 3 and the like? \$\endgroup\$ – Lynn Jan 6 '16 at 1:02
  • \$\begingroup\$ Also, maybe allow / for ÷? \$\endgroup\$ – Lynn Jan 6 '16 at 1:04
  • \$\begingroup\$ Could the operators have the same precedence level as their normal counterparts? \$\endgroup\$ – Brad Gilbert b2gills Jan 6 '16 at 1:57
  • \$\begingroup\$ @ThomasKwa Yes, you could translate Mauris' answer, but much more fun to define an APL operator to do the work. \$\endgroup\$ – Adám Jan 6 '16 at 9:55
4
\$\begingroup\$

CJam, 45 bytes

q"-F"/"1 -"*"+F"/"1Y$-*+"*'F-S/)d\2/'\f*W%S*~

Uses precedence rule 6: strictly right-to-left. It expects ASCII input.

Take it for a spin!

Explanation

Read input, and perform the following transformations in order:

"-F"   to   "1 -"
"+F"   to   "1Y$-*+"
 "F"   to   ""

Then split over spaces (S/). Extract the rightmost element and convert it to a double ()d). Then take pairs from the rest of the list (\2/), join them all by \ ('\f*) and evaluate the resulting strings as CJam code in reverse order (W%S*~).

For example, it converts 5 +F 10 + 3

  • to 5 1Y$-*+ 10 + 3 in the first step,
  • then to 3 [["10" "+"] ["5" "1Y$-*+"]],
  • then to 3 ["10\+" "5\1Y$-*+"],
  • then to 3 10\+ 5\1Y$-*+, which is CJam code that computes the right answer, -47.
\$\endgroup\$
4
\$\begingroup\$

QuadR, 21 bytes

⍎⍵
\+F
-F
F
(+-×)
1-

Try it online! or a version that accepts newline-separated test cases.

QuadR port of Razetime's APL answer, as it happens to be a set of ⎕R substitution followed by post-processing code. I moved ⍵~'F' part into the regex substitution 'F' → '', which saves a byte. It has no problem running multiple test cases separated by , but it does have some problem with newlines (which can be fixed by changing the first line to ⍎⍤1⎕FMT⍵).

\$\endgroup\$
4
\$\begingroup\$

Jelly, 20 bytes

⁾-Cyœṣ⁾+Fj“+_×ɗ”ḟ”FV

Try it online!

To quote myself:

Well, it's disgustingly hacked together, but it works :D


Well, it's much more elegantly hacked together.

Haha, beating QuadR!

Jelly doesn't like strings. For a more elegant solution that exploits Jelly natural infix notation, see below. Takes input from ARGV. The Footer in the link takes a multiline string, splits it on newlines, runs each line and returns a list of results.

This uses precedence rule 5, which is consistent (I believe) with Jelly's parsing rules in this case, and we use _ for regular subtraction and for regular negation.

Takes input with a trailing space (on each line for multiline input), as allowed in chat by OP, which the Footer does for you

How it works

⁾-Cyœṣ⁾+Fj“+_×ɗ”ḟ”FV - Main link. Takes an expression E on the left
⁾-C                  - Yield ["-", "C"]
   y                 - Replace all occurrences of "-" with "C"
      ⁾+F            - Yield ["+", "F"]
    œṣ               - Split on "+F"
          “+_×ɗ”     - Yield "+_×ɗ"
         j           - Join on "+_×ɗ"
                ḟ”F  - Remove any leftover "F"s
                   V - Execute as Jelly code

Why C and +_×ɗ?

First, C. C is Jelly's builtin for \$1 - x\$

Now, +_×ɗ. The ɗ at the end tells Jelly to consider the previous 2 atoms as a single link, acting similarly to (...) in other languages. The three atoms implement the formula

$$\begin{align} 1 - (1-a)(1-b) & = 1 - (1-a-b+ab) \\ & = a+b-ab \end{align}$$

+_× - Takes a on the left and b on the right
+   - a+b
  × - a×b
_   - a+b - a×b

Jelly, 9 + 8 = 17 bytes

×
÷
C
+_×

Try it online! or Try it online!

Slightly convoluted here, but bear with me. This uses the

Alternatively, extend the language of your choice to include the notation.

rule to avoid any parsing or complicated stuff that Jelly isn't too good at. Instead we define 4 functions , , 3Ŀ and (Conjuction, Division, Negation and Disjuction respecitively), which "extends" Jelly to include the fuzzy operations by including the above 11 bytes before any code. I'm counting my byte count here as 11 bytes for the code above plus 8 bytes for the names of the functions.

This uses precedence rule 5, which is consistent (I believe) with Jelly's parsing rules in this case, and we use _ for regular subtraction.

In the test suite above, we include our 4 functions in the header, then execute the lines of test cases with the Footer.

How it works

The names of the functions are fairly easy to understand. Jelly allows you to call each line as a function using the Ŀ (call as monad) or the ŀ (call as dyad) quicks, which is what we use here.

and are obvious how they work. 3Ŀ simply takes advantage of Jelly's builtin for \$1 - x\$: C. works the same way as specified above, but doesn't need the ɗ for grouping

\$\endgroup\$
0
3
\$\begingroup\$

APL (Dyalog Unicode), 38 37 35 30 bytes

⍎'F'~⍨'\+F' '-F'⎕R'(+-×)' '1-'

Try it online!

A tacit function which accepts a string.

Evaluation is done as per Rule 6: strict right to left, as per APL's evaluation.

-1 byte from Adám.

-2 more from Adám.

-5 bytes from Bubbler.

Explanation

⍎'F'~⍨'\+F' '-F'⎕R'(+-×)' '1-'
            '-F'⎕R        '1-'  regex replace '-F' with '1-'
      '\+F'     ⎕R'(+-×)'       regex replace '+F' with function to perform 1-((1-x)×(1-y))
 'F'~⍨                          remove any other Fs
⍎                               execute as APL code
\$\endgroup\$
6
  • \$\begingroup\$ Finally! Thank you. \$\endgroup\$ – Adám Dec 16 '20 at 18:38
  • \$\begingroup\$ I saw this challenge and knew you had to have already implemented it. \$\endgroup\$ – Razetime Dec 17 '20 at 2:48
  • 1
    \$\begingroup\$ Do you know ⎕R can take multiple regexes and transformation patterns at once? \$\endgroup\$ – Adám Dec 17 '20 at 7:58
  • \$\begingroup\$ @Adám forgot about that, -1 \$\endgroup\$ – Razetime Dec 17 '20 at 8:00
  • 1
    \$\begingroup\$ A bit of math: {1-×/1-⍺⍵}(+-×) (TIO) \$\endgroup\$ – Bubbler Dec 17 '20 at 8:26
2
\$\begingroup\$

APL (Dyalog Unicode), 27 24 bytes

Saved 3 bytes thanks to @Adám!

F←{⍺←1⋄⍺(×-⍣(2=⍺⍺2)⍺⍺)⍵}

Try it online!

Extends the language with a monadic operator F. Uses rule 6 (strict right-to-left). This fixes the issues Adám pointed out in the original answer.

⍺⍺ is the input function (+, -, ×, or ÷), is the left argument (⍺←1 gives it a default value of 1), and is the right argument. ×-⍣(2=⍺⍺2)⍺⍺, which Adám came up with, is applied to and . It's equivalent to (⍺×⍵) -⍣(2=⍺⍺2) (⍺ ⍺⍺ ⍵). If ⍺⍺ is +, then 2=⍺⍺2 (2 = +2) is true. If so, subtracts its right argument ⍺+⍵ from its left argument ⍺×⍵ (this is equivalent to 1-(1-⍺)×(1-⍵). Otherwise, we just return what's on the right side. If it's multiplication or division, it's the same as normal × or ÷. If it's fuzzy negation, then is 1, so it'll be 1-⍵.

\$\endgroup\$
4
0
\$\begingroup\$

Nim, 106 bytes

type f=float
func`*~`(a,b:f):f=a*b
func`/~`(a,b:f):f=a/b
func`-~`(b:f):f=1-b
func`+~`(a,b:f):f=1- -~a* -~b

Try it online!

Adds the four operators to Nim. Since operator names can't contain letters, it uses a tilde ~ instead, which I consider a very fuzzy character. Precedence is the same as the corresponding normal operators.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.