Palindrome check — punctuation- and case-insensitive
Strips everything but letters/digits, lowercases, then compares the cleaned string against its reverse. Demonstrates per-character filtering with s[i] and a descending range to build the reverse. Run: soma run palindrome.cell --signal is_palindrome "A man, a plan, a canal: Panama"
A Soma program from the text part of the verified corpus: 54 lines, cells Palindrome, PalindromeTest. It passes soma check with soma 3.2.4.
How it is built
The cell Palindrome declares 2 signals in its face: is_palindrome(s: String) -> Bool and reverse_str(s: String) -> String. Handlers: reverse_str (line 30) and is_palindrome (line 38). Private helpers: _clean.
The file also holds 1 test cell (PalindromeTest) with 6 assertions, run by soma test.
The source
palindrome.cell
// ============================================================================
// Palindrome check — punctuation- and case-insensitive
// ============================================================================
//
// Strips everything but letters/digits, lowercases, then compares the cleaned
// string against its reverse. Demonstrates per-character filtering with s[i]
// and a descending range to build the reverse.
//
// Run: soma run palindrome.cell --signal is_palindrome "A man, a plan, a canal: Panama"
cell Palindrome {
face {
signal is_palindrome(s: String) -> Bool
signal reverse_str(s: String) -> String
}
// Keep only alphanumeric characters, lowercased.
on _clean(s: String) {
let low = lowercase(s)
let out = ""
for i in range(0, len(low)) {
let c = low[i]
if (c >= "a" && c <= "z") || (c >= "0" && c <= "9") {
out = out + c
}
}
return out
}
on reverse_str(s: String) {
let out = ""
for i in range(len(s) - 1, -1, -1) {
out = out + s[i]
}
return out
}
on is_palindrome(s: String) {
let c = _clean(s)
return c == reverse_str(c)
}
}
cell test PalindromeTest {
rules {
assert is_palindrome("racecar")
assert is_palindrome("A man, a plan, a canal: Panama")
assert is_palindrome("Was it a car or a cat I saw?")
assert !is_palindrome("hello")
assert reverse_str("abc") == "cba"
assert is_palindrome("12321")
}
}What the toolchain says
$ soma check palindrome.cell
warning: `out` grows by concatenation inside a loop — each step copies the whole value, so the loop is quadratic (8 MB took 32 s, a list + join() 30 ms): push the pieces to a List and `join(parts, "")` once
--> palindrome.cell:24:17
|
24 | out = out + c
| ^
warning: `out` grows by concatenation inside a loop — each step copies the whole value, so the loop is quadratic (8 MB took 32 s, a list + join() 30 ms): push the pieces to a List and `join(parts, "")` once
--> palindrome.cell:33:13
|
33 | out = out + s[i]
| ^
✓ 2 warning(s), no errors.$ soma test palindrome.cell
test PalindromeTest ...
✓ assert is_palindrome("racecar")
✓ assert is_palindrome("A man, a plan, a canal: Panama")
✓ assert is_palindrome("Was it a car or a cat I saw?")
✓ assert !is_palindrome("hello")
✓ assert reverse_str("abc") == "cba"
✓ assert is_palindrome("12321")
6 tests: 6 passed, 0 failed$ soma verify palindrome.cell
Verifying palindrome.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)