the difference between chains and cochains I have heard the following definitions, for concreteness I will refer a simplicial complex $K$ and a ring $R$, though the definitions can be extended:

A chain is a formal linear combination of simplices in $K$ with coefficients in $R$.


A cochain is a function on simplices, i.e. a map $K \to R$.

I understand that chains and cochains are dual to each other, but I feel that I do not fully understand how the above two statements meaningfully differ.
The way I am currently thinking of it is something like the following. A $p$-chain is a formal linear combination of $p$-simplices, so I can write that as something like this:
$$\vert f_p \rangle = \sum_{i \in I^p} c_i \vert \sigma^p_i \rangle$$
where $I^p$ is an index set for the $p$-simplices in $K$, $\vert \sigma^p_i \rangle$ is a $p$-simplex indexed by $i$, and $c_i \in R$. Then cochains are the "dual vectors". This is where things a little hazy for me, I would assume we can define "co-simplexes" $\langle \sigma^p_i \vert$ as the basis for the cochains via
$$\langle \sigma^p_i \vert \sigma^p_j \rangle = \delta_{ij}$$
where $\delta_{ij}$ is the Kronecker delta. Then the cochains are the dual vectors to the chains
$$\langle {g_p} \vert = \sum_{i \in I^p} \langle \sigma_i^p \vert c_i $$
Is this an accurate way to think about them? I think my confusion is what the difference is between "a function which maps a simplex to a scalar" (cochain) and "a formal linear combination of simplices" (chain), which to me is the same as assigning a scalar value to each simplex. Is there a clear distinction between these two concepts?
In other words, if a cochain is a map $K\to R$, what is a "formal linear combination of elements of $K$"?
 A: Practically, the difference is that if there are infinitely many simplices, a cochain can take nonzero values on all of them, whereas a chain must be a finite linear combination of simplices. In other words, if we think of a chain in terms of its coefficients, those coefficients, regarded as a function on simplices, must be finitely supported. We say that chains must be "compactly supported" (since each simplex is compact).
This leads to a big difference in functoriality: chains push forward and cochains pull back. This is easiest to explain for just bare sets: given a set $X$, "chains on $X$" consists of the free vector space $C_0(X) = \mathbb{R}[X]$, and "cochains on $X$" is the vector space of functions $C^0(X) = \mathbb{R}^X$. (These are in fact the zeroth homology vs. zeroth cohomology of $X$ regarded as a discrete space.) Given a map $f : X \to Y$ of sets, we get a pushforward on chains
$$f_{\ast} : C_0(X) \ni \sum_x c_x x \mapsto \sum_x c_x f(x) \in C_0(Y)$$
and a pullback on cochains
$$f^{\ast} : C^0(Y) \ni c^y \mapsto c^{f(x)} \in C^0(X).$$
Neither of these directions can be reversed in general: we don't get a pullback on chains or a pushforward on cochains (check this; you can take $X$ to be infinite and $Y$ to be a point), and the reason has to do with the finite support condition on chains. However, chains and cochains can be identified if $X$ is finite, and this is a very simple form of Poincare duality.
