u/CodeNameGodTri

▲ 12 r/haskell

newbie learning megaparsec. My code is so mechanical and fragile. Please help.

Hi,

I'm a newbie and I’m working through the CodeCrafters shell challenge in Haskell, specifically the single-quote parsing stage.

https://preview.redd.it/460fqxjtsj9h1.png?width=1694&format=png&auto=webp&s=7070c14c1308836086925b9c16b460aac44b51be

My source code:
https://github.com/tri97nguyen/codecrafters-shell-haskell/blob/6995a88feabc92bdd3e3d5b04912c89675fac196/app/Main.hs

The codebase includes other completed stages, so the relevant entry point is cmdLineArgParser around line 111.

I’m using Megaparsec, and although I’ve learned the basic idea of parser combinators, my solution feels too mechanical and fragile. I keep having to tweak small parser details to force the behavior I want, instead of expressing the grammar clearly.

For example, “parse everything between two single quotes” sounds trivial, but around line 84 I ended up needing logic like:

try . lookAhead $ endQuote

just to make sure I’m not accidentally treating an adjacent quote as the wrong boundary.

The result works, but it does not feel idiomatic. It feels like I’m fighting Megaparsec rather than encoding the grammar. Worse, when I come back to this parser a few days later, I can understand that it works, but not why the structure is the right one.

Is this just the normal learning curve for parser combinators, or is it a sign that I’m modeling the shell grammar at the wrong level? How would you structure this parser so that single quotes, adjacent quoted strings, and unquoted words are handled cleanly?

Thank you for your help!

reddit.com
u/CodeNameGodTri — 10 days ago
▲ 6 r/dotnet+1 crossposts

Is Python a better fit than ASP.NET Core for this kind of data transformation service?

Hello,

I prototyped this data transformation in Python, and the Pandas version is very straightforward.

The logic is roughly:

  • read several SQL Server tables
  • join them by a shared key
  • add computed columns
  • return the final shaped result to downstream clients

When I tried porting it to ASP.NET Core, the code became much more cumbersome. In C#, I would need to:

  • read each table with Dapper or EF Core
  • map each table into dedicated classes
  • build dictionaries keyed by Position_ID
  • manually join the objects
  • create another DTO/class for the final result
  • manually assign all original and computed columns

The result feels much more bloated than the Pandas version. Python’s dynamic DataFrame model makes this kind of column-oriented transformation much easier because I do not need to define a new class every time the output shape changes.

I know this could be done in a stored procedure, which would make the C# layer thinner. However, we are trying to move business logic out of SQL, so that option is not preferred.

For this type of internal data service, where the main job is table joins, reshaping, and computed columns, is it reasonable to use Python instead of ASP.NET Core? Or is there a cleaner C# pattern I should consider before switching stacks?

Python code is here

C# equivalent

u/CodeNameGodTri — 25 days ago
▲ 15 r/haskell

implemented my own splitOn. Feedback needed

Hello everyone,

I'm a beginner looking for feedback. I wrote my own splitOn because words only splits on whitespace, and I didn’t want to pull in the split package just for one small utility function.

I ended up using a State monad approach. I know the state monad is probably overkill here, but I couldn’t think of a more idiomatic Haskell to mutate/build out a new list. I also used Seq to idiomatically access the last item efficiently O(1) instead of List

Please give me feedback on:

  • more idiomatic Haskell style
  • whether State here is considered bad practice
  • other cleaner solution not using State, I initally thought of fold but my brain froze
import Control.Monad.State (State, get, put, runState, execState)
import System.Environment (getEnv)
import Data.Sequence (Seq((:<|), (:|>), Empty), (|>), singleton)
import Data.Foldable (toList)

splitOn :: String -> Char -> [String]
splitOn text delimiter =
    toList $ execState (splitString text) (singleton "")

    where
    splitString :: String -> State (Seq String) ()
    splitString "" = return ()
    splitString (char : tail) = do
        parseChar char
        splitString tail


    parseChar :: Char -> State (Seq String) ()
    parseChar char = do
        currentState <- get
        if char == delimiter then put $ currentState |> ""
        else do
            let (front :|> lastItem) = currentState
                newLastItem = lastItem <> [char]
            put (front :|> newLastItem)

Appreciate any feedback or suggestions.

reddit.com
u/CodeNameGodTri — 2 months ago