| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | Scala 3 | 241027T133358Z | 138 Aspe |
| 073 | Haskell + hgl | 241110T193912Z | Wheat Wi |
| 040 | Prolog SWI | 241027T154756Z | Unrelate |
| 108 | OCaml | 241027T083208Z | Merlin04 |
| 182 | Python3 | 241024T185358Z | Ajax1234 |
| 085 | Python 3 | 241024T231629Z | apilat |
| 038 | oK | 241024T175055Z | zgrep |
| 051 | JavaScript Node.js | 241023T065738Z | l4m2 |
| 040 | Charcoal | 241023T234253Z | Neil |
| 199 | Retina 0.8.2 | 241023T065105Z | Neil |
| 052 | JavaScript Node.js | 241023T070624Z | tsh |
Scala 3, 469 323 bytes
Saved 146 bytes thanks to @noodle person
Golfed version. Attempt This Online!
def f(a:Any,b:Any):Boolean=(a,b)match{case(0,b)=>b==0case(_,0)=>1<2case(x:List[_],y:List[_])=>if(x.isEmpty||y.isEmpty)false
else{val u=x.tail++y.tail
List((List(List(0,2),List(1,3)),1),(List(List(2,0),List(1,3)),2)).exists{case(r,t)=>t==x(0)&&t==y(0) &&r.forall{p=>try{f(u(p(0)),u(p(1)))}catch{case _=>false}}}}case _=>1>2}
Ungolfed version. Attempt This Online!
object Main {
// Helper type for better type safety and pattern matching
type NestedList = Any
def f(a: NestedList, b: NestedList): Boolean = {
(a, b) match {
// Base cases
case (0, b) => b == 0
case (_, 0) => true
// Main recursive case for lists
case (aList: List[_], bList: List[_]) =>
if (aList.isEmpty || bList.isEmpty) return false
// Define conditions similar to Python version
val conditions: List[(List[List[Int]], Int)] = List(
(List(List(0, 2), List(1, 3)), 1),
(List(List(2, 0), List(1, 3)), 2)
)
// Get first elements and remaining lists
val (aHead, aTail) = (aList.head, aList.tail)
val (bHead, bTail) = (bList.head, bList.tail)
// Combine remaining elements
val U = aTail ++ bTail
// Check conditions
conditions.exists { case (r, t) =>
t == aHead && t == bHead && {
// Check all pairs of conditions
r.forall { pair =>
try {
val x = pair(0)
val y = pair(1)
val ux = U(x)
val uy = U(y)
f(ux, uy)
} catch {
case _: Exception => false
}
}
}
}
// Any other case returns false
case _ => false
}
}
def main(args: Array[String]): Unit = {
// Convert Python nested lists to Scala
println(f(0, 0))
println(f(List(2, 0, List(1, 0, 0)), List(2, List(1, 0, 0), 0)))
println(f(List(1, List(2, 0, 0), List(1, 0, 0)), List(1, 0, 0)))
println(f(List(2, 0, List(2, 0, List(2, 0, 0))), List(2, 0, List(2, 0, 0))))
println(f(0, List(2, 0, 0)))
println(f(List(2, 0, 0), List(1, 0, 0)))
println(f(List(2, List(1, 0, 0), 0), List(2, 0, 0)))
println(f(List(1, 0, List(1, 0, 0)), List(1, List(1, 0, 0), 0)))
println(f(List(1, List(2, List(1, 0, 0), 0), 0), List(1, List(1, 0, 0), 0)))
}
}
Haskell + hgl, 73 bytes
_#Pu _=T
Fe(Co(s,[a,c]))#Fe(Co(z,[b,d]))|s,z=a#b<>c#d|s==z=b#a<>c#d
_#_=B
Takes input as a:
Free (Comp ((,) Bool) List) ()
Which is basically a ragged list of ()s where every layer is labelled true (for pairs) or false (for functions).
Reflection
I'm pretty disappointed in this. This was a chance to bring out the more structural side of hgl and it is far to long for my liking.
The main failure here appears to be the pattern matching which takes an enormous portion of the code.
I'm really disappointed that it is cheaper to use
Listinstead ofVec2. ButVec2would have made the pattern matching even longer.I don't like using boolean pairs. Really this should be an either, however
Freerequires one free argument and an either would lead to a splitting. I would have sworn that there was a W combinator for types in hgl, and that would have fixed this issue, but alas it appears not.
In my ideal world the type I would be using would be:
Free (Comp (W Either) Vec2) ()
Not sure this could ever be competitive with a semantically poorer type, but I think it's worth striving for.
Some improvements I would like to see:
- Add a W combinator for types.
- Add a function to do this sort of parallel recursion on free monads. It would really reduce the amount of pattern matching being done.
- Add a pattern which combines
FeandCo. These are common enough combinators and there is good reason to expect them to be combined like this again.
Prolog (SWI), 40 bytes
_+t.
A*B+C*D:-A+C,B+D.
A/B+C/D:-C+A,B+D.
Can't get much more to the point than this! Represents \$\top\$ as the atom t, \$S \times T\$ as the term S * T, and \$S \rightarrow T\$ as the term S / T; outputs through success or failure of the predicate +/2.
Each line is a direct translation of the three bullet points in the spec.
OCaml, 108 bytes
type t=T|D of bool*t*t
let rec h=function D(g,a,b),D(j,c,d)->g=j&&h(if g then c,a else a,c)&&h(b,d)|_,b->b=T
Try it online! (includes test cases)
Input to the function h is a tuple of two values of type t:
- \$\mathbf{Top}\$ is
T - \$S \times T\$ is
D(false, S, T) - \$S \to T\$ is
D(true, S, T).
Python3, 182 bytes
def f(a,b):
if a==0:return b==0
if b==0:return 1
for r,T in[([[0,2],[1,3]],1),([[2,0],[1,3]],2)]:
U=a[1:]+b[1:]
if T==a[0]and T==b[0]and all(f(U[X],U[Y])for X,Y in r):return 1
Python 3, 85 bytes
f=lambda s,t:t==0if t==0 or s==0else(t[0]==s[0])&f(s[2],t[2])&f(*[s[1],t[1]][::s[0]])
Uses 0 for Top, [1,S,T] for \$S \times T\$, [-1,S,T] for \$S \to T\$.
oK, 38 bytes
{$[*x&x=y;&/o.'(.*x;_)@'1_+(x;y);*~y]}
The input is encoded as follows, whether or not it's reasonable depends on how charitable you're feeling:
- \$\textbf{Top}\$ is
0 - \$X \times Y\$ is
(95;X;Y) - \$X \to Y\$ is
(124;X;Y)
Output is 1 for true and 0 for false.
Translation:
{ } /function(x, y):
x=y / ans = (x == y) // element-wise
x& / ans = min(x, ans) // element-wise
* / ans = first(ans)
$[ ; ; ] / if ans:
(x;y) / ans = [x, y]
+ / ans = transpose(ans)
1_ / ans = drop_first(ans)
.*x / f1 = eval(first(x))
/ // eval interprets int as char:
/ // 95 → "_" → floor
/ // 124 → "|" → reverse
_ / f2 = floor
( ; )@' / ans = map(apply, zip([f1, f2], ans))
o / o = this function
.' / ans = map(uncurry, zip([o, o, …], ans))
&/ / return fold(min, ans)
/ else:
*~y / return first(not y)
Explanation:
*x&x=yis true when \$X = Y \not= \textbf{Top}\$- This lets us recurse only when \$X \in \{A \to B, A \times B\}\$ and \$Y \in \{C \to D, C \times D\}\$.
1_+(x;y)gives us the array \$[[A, C], [B, D]]\$(f;g)@'zip-maps, giving \$[f([A, C]), g([B, D])]\$_floor acts as an identity function- If \$X = \cdot \to \cdot\$:
.*xis reverse, so the array is \$[[C, A],[B, D]]\$
- Otherwise:
.*xis floor, so the array is \$[[A, C], [B, D]]\$
- Given \$[[w,z],[B,D]]\$,
o.'recurses to check both \$w <: z\$ and \$B <: D\$. &/returns true iff both are true.
- Otherwise \$\textbf{Top} \in \{X, Y\}\$:
- Return
*~y, which is true iff \$Y = \textbf{Top}\$.
- Return
A similar 38-byte solution:
{$[*x&x=y;&/o.'(^;.*x;_)@'+(x;y);*~y]}
And if the input is a two-element array, as opposed to two arguments:
{$[**x&*=/x;&/o'(.**x;_)@'1_+x;**~|x]}
JavaScript (Node.js), 51 bytes
f=(x,y)=>y?x&&f(x.b,y.b)&f(x.a,y.a)+f(y.A,x.A):x>=x
{A:_,b:_} as arrow, {a:_,b:_} as mult,
Charcoal, 40 bytes
¹⊞υAFυF…§ι¹¦¹¿κ¿⁻κ§§ι⁰¦⁰⎚F²⊞υE⎇∧λ⊖κ⮌ιι⊟μ
Try it online! Link is to verbose version of code. Takes input as a list of the two types and uses [0] for Top and outputs a Charcoal boolean, i.e. 1 for subtype, nothing if not. Explanation:
¹
Assume that the first input element is a subtype of the second.
⊞υAFυ
Start by considering the two input types.
F…§ι¹¦¹
Get the kind of the second type.
¿κ
If the second type is not Top, then...
¿⁻κ§§ι⁰¦⁰⎚
... if the two types are different then they are not subtypes, otherwise...
F²⊞υE⎇∧λ⊖κ⮌ιι⊟μ
... take the two pairs of inner types, reverse the first pair if necessary, and save both pairs for further processing.
Retina 0.8.2, 219 199 bytes
^({(({)|(?<-3>})|\w)+)p((({)|(?<-6>})|\w)+},)({(({)|(?<-9>})|\w)+)p(?(9)^)
$7x$4$1x
^{((({)|(?<-3>})|\w)+)x((({)|(?<-6>})|\w)+)},{((({)|(?<-9>})|\w)+)x((({)|(?<-12>})|\w)+)}$
$1,$7¶$4,$10
+%)A`,T$
^$
Try it online! Link includes test cases. Explanation:
^({(({)|(?<-3>})|\w)+)p((({)|(?<-6>})|\w)+},)({(({)|(?<-9>})|\w)+)p(?(9)^)
$7x$4$1x
Match {S'pT},{SpT'} and turn it into {SxT},{S'xT'}.
^{((({)|(?<-3>})|\w)+)x((({)|(?<-6>})|\w)+)},{((({)|(?<-9>})|\w)+)x((({)|(?<-12>})|\w)+)}$
$1,$7¶$4,$10
Match {SxT},{S'xT'} and split it into S,S' and T,T'.
+%)A`,T$
Delete any conditions where the RHS is T and repeatedly process any remaining conditions.
^$
Check that there are no left-over conditions.
The input format is as follows:
- A condition
S <: Tto be tested takes the formS,TwhereSandTare types. - A type can be of the form
T(representing Top),{SpT}(representingS -> Tor{SxT}(representingS * T). - The test harness allows for multiple conditions each on their own line.
- As a convenience, the test harness also allows
>in place ofp.
JavaScript (Node.js), 52 bytes
f=([a,b,c],[x,y,z])=>~x?a-x||f(c,z)|f(a?y:b,a?b:y):0
Use [-1] for \$\mathbf{Top}\$, [0,S,T] for \$S\times T\$, [1,S,T] for \$S\to T\$.