Q: haskell split function for multi-character delimeter I've seen this code for the split function in Haskell already:
split :: String -> [String]
split [] = [""]
split (c:cs)
   | c == ','  = "" : (split cs)
   | otherwise = (c : head (split cs)) : tail (split cs)

Sample: Input: "1,2,3" Output:["1","2","3"]
However, this code only works when the delimeter is a ','. The code could be changed easily like this:
split :: Char->String -> [String]
split [] = [""]
split d (c:cs)
   | c == d  = "" : (split cs)
   | otherwise = (c : head (split cs)) : tail (split cs)

So that the function works for any single character as the delimeter.
However, I want a function that works when the delimeter is a string itself.
So, I've tried this:
split' :: String -> String -> [String]
split' (d:ds) (c:cs)
    | (d:ds) `isPrefixOf'` (c:cs) = "":rest
    | otherwise = (c:head(split'((d:ds),rest))):tail(split'((d:ds),rest))
  where
     rest = split' (d:ds) drop( length(d:ds) (c:cs) )

where
isPrefixOf'              :: (Eq a) => [a] -> [a] -> Bool
isPrefixOf' [] _         =  True
isPrefixOf' _  []        =  False
isPrefixOf' (x:xs) (y:ys)=  (x == y) && (isPrefixOf' xs ys)

However, I get this ugly error when I load the program:
Prelude> :l testingsplit.hs
[1 of 1] Compiling Main             ( testingsplit.hs, interpreted )

testingsplit.hs:15:27: error:
    • Couldn't match expected type '[[Char]]'
                  with actual type 'String -> [String]'
    • Probable cause: 'split'' is applied to too few arguments
      In the first argument of 'head', namely '(split' ((d : ds), rest))'
      In the second argument of '(:)', namely
        'head (split' ((d : ds), rest))'
      In the first argument of '(:)', namely
        '(c : head (split' ((d : ds), rest)))'
   |
15 |     | otherwise = (c:head(split'((d:ds),rest))):tail(split'((d:ds),rest))
   |                           ^^^^^^^^^^^^^^^^^^^

testingsplit.hs:15:33: error:
    • Couldn't match type '([Char], b0)' with '[Char]'
      Expected type: String
        Actual type: ([Char], b0)
    • In the first argument of 'split'', namely '((d : ds), rest)'
      In the first argument of 'head', namely '(split' ((d : ds), rest))'
      In the second argument of '(:)', namely
        'head (split' ((d : ds), rest))'
   |
15 |     | otherwise = (c:head(split'((d:ds),rest))):tail(split'((d:ds),rest))
   |                                 ^^^^^^^^^^^^^

testingsplit.hs:15:54: error:
    • Couldn't match expected type '[[Char]]'
                  with actual type 'String -> [String]'
    • Probable cause: 'split'' is applied to too few arguments
      In the first argument of 'tail', namely '(split' ((d : ds), rest))'
      In the second argument of '(:)', namely
        'tail (split' ((d : ds), rest))'
      In the expression:
        (c : head (split' ((d : ds), rest)))
          : tail (split' ((d : ds), rest))
   |
15 |     | otherwise = (c:head(split'((d:ds),rest))):tail(split'((d:ds),rest))
   |                                                      ^^^^^^^^^^^^^^^^^^^

testingsplit.hs:15:60: error:
    • Couldn't match type '([Char], b1)' with '[Char]'
      Expected type: String
        Actual type: ([Char], b1)
    • In the first argument of 'split'', namely '((d : ds), rest)'
      In the first argument of 'tail', namely '(split' ((d : ds), rest))'
      In the second argument of '(:)', namely
        'tail (split' ((d : ds), rest))'
   |
15 |     | otherwise = (c:head(split'((d:ds),rest))):tail(split'((d:ds),rest))
   |                                                            ^^^^^^^^^^^^^

testingsplit.hs:17:13: error:
    • Couldn't match expected type 't0 -> t'
                  with actual type '[String]'
    • The function 'split'' is applied to three arguments,
      but its type 'String -> String -> [String]' has only two
      In the expression: split' (d : ds) drop (length (d : ds) (c : cs))
      In an equation for 'rest':
          rest = split' (d : ds) drop (length (d : ds) (c : cs))
    • Relevant bindings include
        rest :: t (bound at testingsplit.hs:17:6)
   |
17 |      rest = split' (d:ds) drop( length(d:ds) (c:cs) )
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

testingsplit.hs:17:27: error:
    • Couldn't match type 'Int -> [a0] -> [a0]' with '[Char]'
      Expected type: String
        Actual type: Int -> [a0] -> [a0]
    • Probable cause: 'drop' is applied to too few arguments
      In the second argument of 'split'', namely 'drop'
      In the expression: split' (d : ds) drop (length (d : ds) (c : cs))
      In an equation for 'rest':
          rest = split' (d : ds) drop (length (d : ds) (c : cs))
   |
17 |      rest = split' (d:ds) drop( length(d:ds) (c:cs) )
   |                           ^^^^

testingsplit.hs:17:33: error:
    • Couldn't match expected type '[Char] -> t0'
                  with actual type 'Int'
    • The function 'length' is applied to two arguments,
      but its type '[Char] -> Int' has only one
      In the third argument of 'split'', namely
        '(length (d : ds) (c : cs))'
      In the expression: split' (d : ds) drop (length (d : ds) (c : cs))
   |
17 |      rest = split' (d:ds) drop( length(d:ds) (c:cs) )
   |                                 ^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

I don't understand where I have gone wrong.
Also, I already know Data.List has the splitOn method, which does this already. However, I am not allowed to use that module for the work I am doing. I am only interested in answers that only use Haskell's Data.Char and the Prelude.

I have a follow-up question: How could I change split' so it works for any type of list in general. I'm not fully sure what type signature I should use.
I've tried this:
split'' :: Eq a => [a] -> [a] -> [[a]]
split'' _ [] = []
split'' [] x = map (:[]) x
split'' a@(d:ds) b@(c:cs)
    | Just suffix <- a `stripPrefix'` b = "":split'' a  suffix
    | otherwise = if null rest
                      then [[c]]
                      else (c:head rest):tail rest
  where
      rest = split'' a $ tail b

stripPrefix' :: Eq a => [a] -> [a] -> Maybe [a]
stripPrefix' [] ys = Just ys
stripPrefix' (x:xs) (y:ys)
    | x == y = stripPrefix' xs ys
stripPrefix' _ _ = Nothing

Now, I get this error about the Char type when I load the program:
[1 of 1] Compiling Main             ( splittest.hs, interpreted )

splittest.hs:24:46: error:
    • Couldn't match type 'a' with 'Char'
      'a' is a rigid type variable bound by
        the type signature for:
          split'' :: forall a. Eq a => [a] -> [a] -> [[a]]
        at splittest.hs:20:1-38
      Expected type: [[Char]]
        Actual type: [[a]]
    • In the second argument of '(:)', namely 'split'' a suffix'
      In the expression: "" : split'' a suffix
      In an equation for 'split''':
          split'' a@(d : ds) b@(c : cs)
            | Just suffix <- a `stripPrefix'` b = "" : split'' a suffix
            | otherwise
            = if null rest then [[c]] else (c : head rest) : tail rest
            where
                rest = split'' a $ tail b
    • Relevant bindings include
        suffix :: [a] (bound at splittest.hs:24:12)
        rest :: [[a]] (bound at splittest.hs:29:7)
        cs :: [a] (bound at splittest.hs:23:23)
        c :: a (bound at splittest.hs:23:21)
        b :: [a] (bound at splittest.hs:23:18)
        ds :: [a] (bound at splittest.hs:23:14)
        (Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
   |
24 |     | Just suffix <- a `stripPrefix'` b = "":split'' a  suffix
   |                                              ^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

I'm new to Haskell, so I don't know where I have made a mistake.
Also, thank you for your earlier reply. It was very helpful and detailed.

A: Your code has many things wrong with it, including bad spacing and repetition of (d:ds) and (c:cs) when you could just give the whole thing a name by taking a@(d:ds) as an argument. However, these are all just stylistic errors. The biggest error in your code is the fact that you're trying to call functions like python, where it's the function name followed by parentheses followed by a comma separated list of arguments. Haskell does not work like this. Function arguments are separated by spaces, and you don't need parentheses after the function call. If you comma-separate arguments, you just create a tuple and call the function on that tuple, which breaks the whole thing. Here's your cleaned up code:
split' :: String -> String -> [String]
split' a@(d:ds) b@(c:cs)
    | a `isPrefixOf'` b = "":rest
    | otherwise = (c:head (split' a rest)):tail (split' a rest)
  where
     rest = split' a $ drop (length a) b

Isn't this much nicer to read? Unfortunately, this still doesn't work. rest already has split' a called on it, so you don't need to call split' a on it again in the body of your function:
split' :: String -> String -> [String]
split' a@(d:ds) b@(c:cs)
    | a `isPrefixOf'` b = "":rest
    | otherwise = (c:head rest):tail rest
  where
      rest = split' a $ drop (length a) b

Now, this compiles, but it still doesn't work:
λ> split' ", " "1, 2, 3"
["1 ","3*** Exception: Non-exhaustive patterns in function split'

This would be indicative of the fact that we have to add our base cases:
split' :: String -> String -> [String]
-- splitting nothing is nothing
split _ [] = []
-- splitting on empty string just returns array of individual chars
split [] x = map (:[]) x
split' a@(d:ds) b@(c:cs)
    | a `isPrefixOf'` b = "":rest
    | otherwise = (c:head rest):tail rest
  where
      rest = split' a $ drop (length a) b

Now, this compiles, but still has non-exhaustive patterns:
λ> split' ", " "1, 2, 3"
["1 ","3*** Exception: Non-exhaustive patterns in function split'

This time, it's because rest could be an empty list. So, we should check for that:
split' :: String -> String -> [String]
split _ [] = []
split [] x = map (:[]) x
split' a@(d:ds) b@(c:cs)
    | a `isPrefixOf'` b = "":rest
    | otherwise = if null rest
                      -- if rest is empty we default to just the one character
                      then [[c]]
                      else (c:head rest):tail rest
  where
      rest = split' a $ drop (length a) b

This still doesn't work, since we're removing the length of the delimiter every time, but we really only want to do that if we find a match. If we don't find a match, we should only drop one character.
The final working code is:
split' :: String -> String -> [String]
split' _ [] = []
split' [] x = map (:[]) x
split' a@(d:ds) b@(c:cs)
    | a `isPrefixOf'` b = "":(split' a $ drop (length a) b)
    | otherwise = if null rest
                      then [[c]]
                      else (c:head rest):tail rest
  where
      rest = split' a $ tail b

As a side note, your code can be cleaned up by using stripPrefix in Data.List instead of isPrefixOf', which allows you to save a drop and avoid iterating over the list twice:
import Data.List

split' :: String -> String -> [String]
split' _ [] = []
split' [] x = map (:[]) x
split' a@(d:ds) b@(c:cs)
    | Just suffix <- a `stripPrefix` b = "":split' a  suffix
    | otherwise = if null rest
                      then [[c]]
                      else (c:head rest):tail rest
  where
      rest = split' a $ tail b

It's also pretty easy to implement yourself:
stripPrefix :: Eq a => [a] -> [a] -> Maybe [a]
stripPrefix [] ys = Just ys
stripPrefix (x:xs) (y:ys)
    | x == y = stripPrefix xs ys
stripPrefix _ _ = Nothing

Here's the generic version:
import Data.List

split' :: (Eq a) => [a] -> [a] -> [[a]]
split' _ [] = []
split' [] x = map (:[]) x
split' a@(d:ds) b@(c:cs)
    | Just suffix <- a `stripPrefix` b = []:split' a  suffix
    | otherwise = if null rest
                      then [[c]]
                      else (c:head rest):tail rest
  where
      rest = split' a $ tail b

