You generally use the Haskell type system to define the DAG associated with the computation you want to run, and the algorithms in terms of functions applied to those DAG nodes. Since the whole DAG is naturally thought of as a big function composed of many small functions applied to slices of (intermediate) data, you can leverage higher order functions in the construction of the DAG around implementations of the numerical code written in, say, C or FORTRAN. This is actually how a lot of numerics in Python is done (or at least was, the last time I looked in to it heavily).
You'd use the FFI to call out to something like C to actually execute the tensor operation, much like the TF design, where you're constructing a DAG in Python of the dataflow through tensors, which have their implementations in another language.
The type system just gives you a powerful way to reason about the structure of your DAG, define higher level abstractions (eg, autoimplementing certain kinds of networks against a certain input type), or discuss the feedback of the system during training, since training is just a higher order function that takes the entire DAG function as input and returns a new DAG. (Okay, for performance reasons you generally update values, but you can model that easily enough in Haskell.)
So really, basically the same way Python for numerics -- calling C for number crunching and doing algorithm designing in the higher level language.