├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "ttti-rs" 5 | version = "0.1.0" 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ttti-rs" 3 | version = "0.1.0" 4 | authors = ["insou22 "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typing the technical interview, translated from Haskell to Rust 2 | 3 | ``` 4 | % cargo run 5 | Finished dev [unoptimized + debuginfo] target(s) in 0.02s 6 | Running `target/debug/ttti-rs` 7 | 8 | Cons>>>>, S>, Cons>>>, S>>>, Cons>>, S>>>>>, Cons>, Z>, Cons, S>>, Cons>>>>, Nil>>>>>> 9 | ``` 10 | 11 | ## Original Article 12 | 13 | https://aphyr.com/posts/342-typing-the-technical-interview 14 | 15 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "1024"] // necessary to generate solutions past N = 6 2 | use std::marker::PhantomData; 3 | 4 | ////////// List ////////// 5 | 6 | struct Nil; 7 | struct Cons(PhantomData<(X, Xs)>); 8 | 9 | 10 | ////////// First ////////// 11 | 12 | trait First { 13 | type Output; 14 | } 15 | 16 | impl First for Nil { 17 | type Output = Nil; 18 | } 19 | 20 | impl First for Cons { 21 | type Output = X; 22 | } 23 | 24 | 25 | ////////// ListConcat ////////// 26 | 27 | trait ListConcat { 28 | type Output; 29 | } 30 | 31 | impl ListConcat for (Nil, L2) { 32 | type Output = L2; 33 | } 34 | 35 | impl ListConcat for (Cons, L2) 36 | where 37 | (Xs, L2): ListConcat, 38 | { 39 | type Output = Cons::Output>; 40 | } 41 | 42 | 43 | ////////// ListConcatAll ////////// 44 | 45 | trait ListConcatAll { 46 | type Output; 47 | } 48 | 49 | impl ListConcatAll for Nil { 50 | type Output = Nil; 51 | } 52 | 53 | impl ListConcatAll for Cons 54 | where 55 | Ls: ListConcatAll, 56 | (L, ::Output): ListConcat, 57 | { 58 | type Output = <(L, ::Output) as ListConcat>::Output; 59 | } 60 | 61 | 62 | ////////// Bool ////////// 63 | 64 | struct False; 65 | struct True; 66 | 67 | trait Bool {} 68 | 69 | impl Bool for False {} 70 | impl Bool for True {} 71 | 72 | 73 | ////////// AnyTrue ////////// 74 | 75 | trait AnyTrue { 76 | type Output: Bool; 77 | } 78 | 79 | impl AnyTrue for Nil { 80 | type Output = False; 81 | } 82 | 83 | impl AnyTrue for Cons { 84 | type Output = True; 85 | } 86 | 87 | impl AnyTrue for Cons 88 | where 89 | L: AnyTrue, 90 | { 91 | type Output = ::Output; 92 | } 93 | 94 | 95 | ////////// Not ////////// 96 | 97 | trait Not { 98 | type Output: Bool; 99 | } 100 | 101 | impl Not for False { 102 | type Output = True; 103 | } 104 | 105 | impl Not for True { 106 | type Output = False; 107 | } 108 | 109 | 110 | ////////// Or ////////// 111 | 112 | trait Or { 113 | type Output: Bool; 114 | } 115 | 116 | impl Or for (True, True) { 117 | type Output = True; 118 | } 119 | 120 | impl Or for (True, False) { 121 | type Output = True; 122 | } 123 | 124 | impl Or for (False, True) { 125 | type Output = True; 126 | } 127 | 128 | impl Or for (False, False) { 129 | type Output = False; 130 | } 131 | 132 | 133 | ////////// Nats ////////// 134 | 135 | struct Z; 136 | struct S(PhantomData); 137 | 138 | type N0 = Z; 139 | type N1 = S; 140 | type N2 = S; 141 | type N3 = S; 142 | type N4 = S; 143 | type N5 = S; 144 | type N6 = S; 145 | 146 | trait Nat {} 147 | impl Nat for Z {} 148 | impl Nat for S {} 149 | 150 | 151 | ////////// PeanoEqual ////////// 152 | 153 | trait PeanoEqual { 154 | type Output: Bool; 155 | } 156 | 157 | impl PeanoEqual for (Z, Z) { 158 | type Output = True; 159 | } 160 | 161 | impl PeanoEqual for (Z, S) 162 | where 163 | N: Nat, 164 | { 165 | type Output = False; 166 | } 167 | 168 | impl PeanoEqual for (S, Z) 169 | where 170 | N: Nat, 171 | { 172 | type Output = False; 173 | } 174 | 175 | impl PeanoEqual for (S, S) 176 | where 177 | N1: Nat, 178 | N2: Nat, 179 | (N1, N2): PeanoEqual, 180 | { 181 | type Output = <(N1, N2) as PeanoEqual>::Output; 182 | } 183 | 184 | 185 | ////////// PeanoLT ////////// 186 | 187 | trait PeanoLT { 188 | type Output: Bool; 189 | } 190 | 191 | impl PeanoLT for (Z, Z) { 192 | type Output = False; 193 | } 194 | 195 | impl PeanoLT for (S, Z) { 196 | type Output = False; 197 | } 198 | 199 | impl PeanoLT for (Z, S) { 200 | type Output = True; 201 | } 202 | 203 | impl PeanoLT for (S, S) 204 | where 205 | N1: Nat, 206 | N2: Nat, 207 | (N1, N2): PeanoLT, 208 | { 209 | type Output = <(N1, N2) as PeanoLT>::Output; 210 | } 211 | 212 | 213 | ////////// PeanoAbsDiff ////////// 214 | 215 | trait PeanoAbsDiff { 216 | type Output: Nat; 217 | } 218 | 219 | impl PeanoAbsDiff for (Z, Z) { 220 | type Output = Z; 221 | } 222 | 223 | impl PeanoAbsDiff for (Z, S) { 224 | type Output = S; 225 | } 226 | 227 | impl PeanoAbsDiff for (S, Z) { 228 | type Output = S; 229 | } 230 | 231 | impl PeanoAbsDiff for (S, S) 232 | where 233 | N1: Nat, 234 | N2: Nat, 235 | (N1, N2): PeanoAbsDiff, 236 | { 237 | type Output = <(N1, N2) as PeanoAbsDiff>::Output; 238 | } 239 | 240 | 241 | ////////// Range ////////// 242 | 243 | trait Range { 244 | type Output; 245 | } 246 | 247 | impl Range for Z { 248 | type Output = Nil; 249 | } 250 | 251 | impl Range for S 252 | where 253 | N: Nat + Range, 254 | { 255 | type Output = Cons::Output>; 256 | } 257 | 258 | 259 | ////////// Higher order functions ////////// 260 | 261 | trait Apply { 262 | type Output; 263 | } 264 | 265 | struct Conj1(PhantomData); 266 | 267 | impl Apply for Conj1 { 268 | type Output = Cons; 269 | } 270 | 271 | 272 | ////////// Map ////////// 273 | 274 | trait Map { 275 | type Output; 276 | } 277 | 278 | impl Map for (F, Nil) { 279 | type Output = Nil; 280 | } 281 | 282 | impl Map for (F, Cons) 283 | where 284 | F: Apply, 285 | (F, Xs): Map, 286 | { 287 | type Output = Cons<>::Output, <(F, Xs) as Map>::Output>; 288 | } 289 | 290 | 291 | ////////// MapCat ////////// 292 | 293 | trait MapCat { 294 | type Output; 295 | } 296 | 297 | impl MapCat for (F, L) 298 | where 299 | (F, L): Map, 300 | <(F, L) as Map>::Output: ListConcatAll, 301 | { 302 | type Output = <<(F, L) as Map>::Output as ListConcatAll>::Output; 303 | } 304 | 305 | 306 | ////////// AppendIf ////////// 307 | 308 | trait AppendIf { 309 | type Output; 310 | } 311 | 312 | impl AppendIf for (True, X, Ys) { 313 | type Output = Cons; 314 | } 315 | 316 | impl AppendIf for (False, X, Ys) { 317 | type Output = Ys; 318 | } 319 | 320 | 321 | ////////// Filter ////////// 322 | 323 | trait Filter { 324 | type Output; 325 | } 326 | 327 | impl Filter for (F, Nil) { 328 | type Output = Nil; 329 | } 330 | 331 | impl Filter for (F, Cons) 332 | where 333 | F: Apply, 334 | (F, Xs): Filter, 335 | (>::Output, X, FilterOutput): AppendIf, 336 | { 337 | type Output = <(>::Output, X, <(F, Xs) as Filter>::Output) as AppendIf>::Output; 338 | } 339 | 340 | 341 | ////////// Queen ////////// 342 | 343 | struct Queen(PhantomData<(X, Y)>); 344 | struct Queen1(PhantomData); 345 | 346 | impl Apply for Queen1 { 347 | type Output = Queen; 348 | } 349 | 350 | 351 | ////////// QueensInRow ////////// 352 | 353 | trait QueensInRow { 354 | type Output; 355 | } 356 | 357 | impl QueensInRow for (N, X) 358 | where 359 | N: Range, 360 | (Queen1, ::Output): Map, 361 | { 362 | type Output = <(Queen1, ::Output) as Map>::Output; 363 | } 364 | 365 | 366 | ////////// Threatens ////////// 367 | 368 | trait Threatens { 369 | type Output: Bool; 370 | } 371 | 372 | impl Threatens for (Queen, Queen) 373 | where 374 | (Ax, Bx): PeanoEqual, 375 | (Ay, By): PeanoEqual, 376 | (Ax, Bx): PeanoAbsDiff, 377 | (Ay, By): PeanoAbsDiff, 378 | (<(Ax, Bx) as PeanoEqual>::Output, <(Ay, By) as PeanoEqual >::Output): Or, 379 | (<(Ax, Bx) as PeanoAbsDiff>::Output, <(Ay, By) as PeanoAbsDiff>::Output): PeanoEqual, 380 | (<(<(Ax, Bx) as PeanoEqual>::Output, <(Ay, By) as PeanoEqual >::Output) as Or>::Output, <(<(Ax, Bx) as PeanoAbsDiff>::Output, <(Ay, By) as PeanoAbsDiff>::Output) as PeanoEqual>::Output): Or, 381 | { 382 | type Output = < 383 | ( 384 | <( 385 | <(Ax, Bx) as PeanoEqual>::Output, 386 | <(Ay, By) as PeanoEqual>::Output, 387 | ) as Or>::Output, 388 | <( 389 | <(Ax, Bx) as PeanoAbsDiff>::Output, 390 | <(Ay, By) as PeanoAbsDiff>::Output, 391 | ) as PeanoEqual>::Output, 392 | ) as Or>::Output; 393 | } 394 | 395 | struct Threatens1(PhantomData); 396 | impl Apply for Threatens1 397 | where 398 | (Qa, Qb): Threatens, 399 | { 400 | type Output = <(Qa, Qb) as Threatens>::Output; 401 | } 402 | 403 | 404 | ////////// Safe ////////// 405 | 406 | trait Safe { 407 | type Output: Bool; 408 | } 409 | 410 | impl Safe for (C, Q) 411 | where 412 | ( Threatens1, C): Map, 413 | <( Threatens1, C) as Map>::Output: AnyTrue, 414 | <<(Threatens1, C) as Map>::Output as AnyTrue>::Output: Not, 415 | { 416 | type Output = <<<(Threatens1, C) as Map>::Output as AnyTrue>::Output as Not>::Output; 417 | } 418 | 419 | struct Safe1(PhantomData); 420 | impl Apply for Safe1 421 | where 422 | (C, Q): Safe, 423 | { 424 | type Output = <(C, Q) as Safe>::Output; 425 | } 426 | 427 | 428 | ////////// AddQueen ////////// 429 | 430 | trait AddQueen { 431 | type Output; 432 | } 433 | 434 | impl AddQueen for (N, X, C) 435 | where 436 | (N, X): QueensInRow, 437 | (Safe1, <(N, X) as QueensInRow>::Output): Filter, 438 | (Conj1, <(Safe1, <(N, X) as QueensInRow>::Output) as Filter>::Output): Map, 439 | { 440 | type Output = <(Conj1, <(Safe1, <(N, X) as QueensInRow>::Output) as Filter>::Output) as Map>::Output; 441 | } 442 | 443 | struct AddQueen2(PhantomData<(N, X)>); 444 | impl Apply for AddQueen2 445 | where 446 | (N, X, C): AddQueen, 447 | { 448 | type Output = <(N, X, C) as AddQueen>::Output; 449 | } 450 | 451 | 452 | trait AddQueenToAll { 453 | type Output; 454 | } 455 | 456 | impl AddQueenToAll for (N, X, Cs) 457 | where 458 | (AddQueen2, Cs): MapCat, 459 | { 460 | type Output = <(AddQueen2, Cs) as MapCat>::Output; 461 | } 462 | 463 | 464 | ////////// AddQueensIf ////////// 465 | 466 | trait AddQueensIf { 467 | type Output; 468 | } 469 | 470 | impl AddQueensIf for (False, N, X, Cs) { 471 | type Output = Cs; 472 | } 473 | 474 | impl AddQueensIf for (True, N, X, Cs) 475 | where 476 | X: Nat, 477 | (N, X, Cs): AddQueenToAll, 478 | (N, S, AddQueenToAllOutput): AddQueens, 479 | { 480 | type Output = <(N, S, <(N, X, Cs) as AddQueenToAll>::Output) as AddQueens>::Output; 481 | } 482 | 483 | 484 | trait AddQueens { 485 | type Output; 486 | } 487 | 488 | impl AddQueens for (N, X, Cs) 489 | where 490 | (X, N): PeanoLT, 491 | (PeanoLTOutput, N, X, Cs): AddQueensIf, 492 | { 493 | type Output = <(<(X, N) as PeanoLT>::Output, N, X, Cs) as AddQueensIf>::Output; 494 | } 495 | 496 | 497 | ////////// Solution ////////// 498 | 499 | trait Solution { 500 | type Output; 501 | } 502 | 503 | impl Solution for N 504 | where 505 | N: Nat, 506 | (Z, N): PeanoLT, 507 | (<(Z, N) as PeanoLT>::Output, N, Z, Cons): AddQueensIf, 508 | AddQueensIfOutput: First, 509 | { 510 | type Output = <<(N, Z, Cons) as AddQueens>::Output as First>::Output; 511 | } 512 | 513 | 514 | ////////// Reify ////////// 515 | 516 | fn main() { 517 | println!("{}", std::any::type_name::< ::Output >().replace("ttti_rs::", "")); 518 | } 519 | --------------------------------------------------------------------------------