A high-performance, Pythonic language for bioinformatics
seqc
now correctly reads from stdin by default or when passed -
as input fileVersion 0.10 brings a slew of improvements to the language and compiler, including:
[]
,{}
), lambda functions (lambda
), *args
/**kwargs
, None
and much moreseqc
The seqc
command’s syntax and default behavior has changed in v0.10:
-release
flag.seqc
has three modes to choose from (use -help
on any of these for more info):
seqc run
)seqc build
)seqc doc
)seqc run program.seq
Seq 0.10 ships with the completely revamped bi-directional type system. Here is a short gist of the new type system in action:
a = []
for i in range(3):
a.append(i)
print a # it is a List[int] with [1, 2, 3]
b = None if len(a) else [1, 3] # b is Optional[List[int]]
b.append(3) # either appends 3 or raises an error if b is None
def foo[T: int, TA = int](a, b: Optional[Function[TA, TA]] = None):
if isinstance(TA, int):
if T < 4:
return a
else:
return 1.1
else:
return f'modified {b(a)+T}'
def adder(a, b):
return a + b ** 2
print foo[1](1) # 1 of type int
print foo[5](1) # 1.1 of type float
print foo[1](2, adder(3, ...)) # 'modified 8' of type string
Major highlights:
a = []
a.append(1)
print a
Optional[T]
handling (assignments, if-else
expressions, calls and dot-expressions automatically wrap or unwrap Optional[T]
)
a = None
a = 5 # a is now Optional[int]
a + 1 # 6 as a gets unwrapped
b = 1 if foo() else None # b is Optional[int]
def foo[N: int]():
print N
foo[4]() # 4
# static integers can be passed from the command line:
# seqc -DK=5 foo.seq
k = Kmer[K] # becomes Kmer[5]
k = Kmer[1 if K > 2 else 4] # also works as this is a static expression
if K > 3:
# <something>; compiled only if K > 3 at the compiile-time
else:
# <something else>
isinstance
, hasattr
and staticlen
, as well as compile-time static expressionsAll Python objects are not first-class Seq objects:
from python import numpy as np
a = np.array(2, 2)
print a[0,1].pow()
Tuple classes:
@tuple
class Foo: # instead of type Foo(x: T)
x: T
Type extension:
@extend
class Foo: # instead of extend Foo
Auto-deduction of self
type:
class Foo[T]:
def bar(self, x): # instead of bar(self: Foo[T], x)
Support for lambdas:
print list(map(range(5), lambda x: x + 1)) # [1, 2, 3, 4, 5]
Python 3 print function:
print(a, b, sep='~', end='!', file=fo)
print a # this is still supported
Mypy-style naming:
List[int] # not list[int]
Dict[int, Tuple[int]] # not dict[int,tuple[int]]
Callable[[int, int], void] # not function[void,int,int]
Relative and recursive import support:
from .. import foo
C, Python and LLVM imports:
from C import pow(float, float) -> float # instead of cimport pow
from C import library.foo(int)
from python import numpy
from python import os.system(str) -> str # instead of pyimport
@python
def foo(): # instead of pydef foo()
print sys.path
@llvm
def bar(x: T) -> Ptr[byte]:
%0 = {=T}* nullptr
ret i8* %0
Walrus (assign) expression:
if (x := foo()):
print x
loop-else
support
for i in bar(): pass
else: print 'no break'
while foo(): pass
else: print 'no break'
123u
12i14
or 234u615
Int[N].__new__(str)
to parse such numbers010101b
123_456
or 0001_0101b
123sfx
→ int.__suffix_sfx__("123")
123.sfx
→ float.__suffix_sfx__("123.")
1e2
is parsed as a float, not as an integer with suffix e2
pfx"hi"
→ str.__prefix_pfx__[2]("hi")
(length si passed as a static integer)[1, *args, 2]
if args
supports __iter__
{1, *args, 2}
if args
supports __iter__
{a: b, **args}
if args
supports __iter__
that returns Tuple[K, V]
foo(a, *args, **kwargs)
args
must be a tuple (lists and named t won’t work). Named tuples are OK.kwargs
must be a named tuple (@tuple class
)for
loops and comprehensions: for i, *_, (k, l) in foo
or [a(b) for _, b in c.items()]
a if b else c
, unary operators [not,-]
, binary operators [+,-,*,//,%]
, conditional operators [==,!=,<,<=,>,>=,and,or]
and the following static calls:
staticlen(tuple)
isinstance(var, type)
hasattr(type, "attr")
compile_error("str")
def foo(a, b, c=1): … ; p = foo(1, …, …); p(b=2)
…
(no more auto-partialization except in pipe expression)Slice[Optional[int],Optional[int,Optional[int]]
for start:stop:step
if a := foo(): …
if a or (b := foo())
won’t compile__ptr__
is a proper expression nowa: List[int] = []
print
function
print
followed by a whitespace is a statement; print
that is not is a identifierassert
statement: assert foo(), f"Failed! {bar}"
for
loop:
a = (1, 's', 5.5); for i in a: print(i)
for i, a in enumerate((1, 's')): …
)match
statement:
case
checks for correct type; if a expression type is incorrect, the corresponding case is ignored__match__
magiccase x or y
is now case x | y
__dict__(self) -> List[str]
that returns list of class member names__contains__
works on heterogeneous tuples__name__
a is b
checkSlice()
)Optional[T]
and pyobj
forward their method calls__atomic_op__
and __atomic_xchg__
)