First let me add my standard remark that if you find yourself thinking about indices in a list you should reconsider your entire approach. It's better to think of lists as streams of values, where you never really care about absolute position but only about the values and possibly their relative order. If you really need indices, you should probably be using Vectors instead of lists.
But ok. If you would use a loop for some task in an imperative language, the obvious approach is always to use recursion in a functional language. Often it's not the most concise, reliable or efficient option, but it's what is always possible and you should certainly practice how to do it.
Basically you write a go function that has an i argument which is “incremented” for each recursive call much like the counter variable in a for loop, and the result is just a list which is build by purely prepending elements when i is in the indices list. Do implement this as an exercise.
But, yes, you could also use filter instead. The trick is that instead of manually maintaining a counter variable, you just add that information to the list as it were. In fact that's something often done even in Python
for i,x in enumerate(myList):
...
In Haskell, thanks to lazy evaluation, enumerate doesn't need any special iterable magic but can be expressed as a simple list zip: in fact the above Python loop could be written in e.g. the IO monad as
forM_ (zip [0..] myList) $ \(i,x) -> do
...
But here you don't really want to loop over the list, only, indeed, filter on it. Namely, you want to retain all the elements whose index is in the list of requested indices:
[ x | (i,x) <- zip [0..] myList, i`elem`myIndices ]
Note that elem has bad performance though: it'll go through all the requested indices for all elements in myList, whereas if myIndices is sorted it would be enough to check only the head element. That's what you could do better in a recursive solution, or alternatively by using the State monad to pop the used indices.
But a rather nicer approach is to create a “masking” list from the list of indices, i.e. turning [1,3,5] into [False, True, False, True, False, True]. This could again be done with manual recursion, or with a trick like this:
indicesAsMask :: [Int] -- Must be strictly sorted
-> [Bool]
indicesAsMask ixs@(0:_) = True : do
(il, ir) <- zip ixs $ tail ixs
replicate (ir - il - 1) False ++ [True]
indicesAsMask ixs = False : tail (indicesAsMask $ 0:ixs)
Then you can simply zip your list together with the mask, and filter out those elements whose mask value is True.