Developing an application from scratch (Haskell Unfolder #46)

The announcement at the start of this thread, as well as the video description on YouTube, attempts to do precisely that:

In this episode targeted at beginners, we show the end-to-end application development process, starting from an empty directory. We’ll consider package configuration, taking advantage of editor integration, how to deal with dependencies, organizing code into modules, and parsing command line arguments. We will use this to write a simple but useful application.

3 Likes

If (as mentioned at 00:36:24) the layout is to emphasize the “structure” (so I guess: systematic — not accidental — commonality between close parts) of code, should friendlyAt be formatted as follows or would that be overdoing it?

friendly :: Cmdline -> String -> String
friendly cmdline = friendlyAt 0
  where
    friendlyAt :: Int -> [Char] -> [Char]
    friendlyAt _ []     = []
    friendlyAt i (c:cs)
      | elem c "{[" =                    [c] ++ newline (i + 1) ++ friendlyAt (i + 1) cs
      | elem c "}]" = newline (i - 1) ++ [c]                    ++ friendlyAt (i - 1) cs
      | c == ','    = newline  i      ++ [c]                    ++ friendlyAt  i      cs
      | otherwise   =                    [c]                    ++ friendlyAt  i      cs

    newline :: Int -> String
    newline i = "\n" ++ replicate (i * cmdline.indent) ' '
1 Like

FWIW, I tried to use GitHub Copilot to do that with this simple Main.hs:

module Main(main) where

import Data.Aeson

main :: IO ()
main = pure ()

The prompt was:

I want to promote this plain Haskell file to a proper Cabal package. Examine the module imports and generate a minimalistic yet modern Cabal file that depends on the corresponding Hackage packages and has the this file as the source code of an executable component.

And it did a reasonable job:

cabal-version: 3.0

name:                bar
version:             0.1.0.0
build-type:          Simple

executable bar
  main-is:             Main.hs
  hs-source-dirs:      .
  default-language:    Haskell2010
  build-depends:
    base >=4.14 && <5,
    aeson

It could be simpler, because build-type is optional. I expect Copilot to be bad at estimating reasonable version bounds though.

2 Likes

I do this kind of stuff often. I don’t think it’s overdoing it. At the same time, I wouldn’t necessarily reformat every single function in order to create this kind of layout. But if there’s a piece of code where I e.g. thought long about the structure and even perhaps got it wrong at first, then I think it’s time well invested if you can make the structure of the code more obvious so that you will more easily recognise it again in case you have to revisit or refactor it.

3 Likes

Cools, I asked for updates (if any)

1 Like

Thanks a lot for the helpful answer.
Finding these links is quite hard.

1 Like