Skip to content

Instantly share code, notes, and snippets.

@tfausak
Last active November 18, 2018 21:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tfausak/cc381ddd0ddd8304cc3eae6250966f55 to your computer and use it in GitHub Desktop.
Save tfausak/cc381ddd0ddd8304cc3eae6250966f55 to your computer and use it in GitHub Desktop.
Analyzes 2018 state of Haskell survey responses. https://github.com/tfausak/tfausak.github.io/pull/148
#!/usr/bin/env stack
-- stack --resolver lts-10.0 script
module Main
( main
)
where
import qualified Control.Monad as Monad
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.Colour.SRGB as Color
import qualified Data.Csv as Csv
import qualified Data.Maybe as Maybe
import qualified Data.Set as Set
import qualified Data.Text as Text
import qualified Data.Time as Time
import qualified Data.Vector as Vector
import qualified Graphics.Rendering.Chart.Backend.Diagrams as Diagrams
import qualified Graphics.Rendering.Chart.Easy as Chart
import qualified System.Directory as Directory
import qualified System.Environment as Environment
import qualified System.FilePath as FilePath
import qualified System.IO as IO
import qualified Text.Printf as Printf
-- Unfortunately there were a large number of bogus submissions. Of the 5,094
-- submissions received, 3,417 of them appear to be submitted by a script.
-- Fortunately they are pretty easy to spot. This function is responsible for
-- identifying them.
shouldIgnore :: Response -> Bool
shouldIgnore response =
contains "Linux" (responseQ25 response) -- Which platforms do you target?
&& contains "GHC" (responseQ28 response) -- Which Haskell compilers do you use?
&& contains "Stack" (responseQ30 response) -- Which installation methods do you use for your Haskell compiler?
&& is "Yes" (responseQ32 response) -- Has upgrading your Haskell compiler broken your code in the last year?
&& is "I dislike it" (responseQ36 response) -- How do you feel about the new GHC release schedule?
&& contains "Stack" (responseQ41 response) -- Which build tools do you use for Haskell?
&& Maybe.isNothing (responseQ95 response) -- Which country do you live in?
&& Maybe.isNothing (responseQ98 response) -- Do you identify as transgender?
&& Maybe.isNothing (responseQ99 response) -- Are you a student?
&& Maybe.isNothing (responseQ104 response) -- How many years have you been coding professionally?
&& Maybe.isNothing (responseQ105 response) -- Do you code as a hobby?
&& Maybe.isNothing (responseQ110 response) -- Do you have any feedback about the survey itself?
main :: IO ()
main = do
arguments <- Environment.getArgs
file <- case arguments of
[file] -> pure file
_ -> fail $ "unexpected arguments: " ++ show arguments
contents <- LazyByteString.readFile file
allResponses <- either fail pure $ Csv.decode Csv.HasHeader contents
let responses = Vector.filter (not . shouldIgnore) allResponses
let
numAll = Vector.length allResponses
numGood = Vector.length responses
numBad = numAll - numGood
Printf.printf "%d good, %d bad, %d total\n" numGood numBad numAll
Directory.createDirectoryIfMissing True outputDirectory
handle <- IO.openFile
(FilePath.combine outputDirectory $ FilePath.addExtension "index" "html")
IO.WriteMode
IO.hPutStrLn handle "<!doctype html>"
IO.hPutStrLn handle "<html>"
IO.hPutStrLn handle "<meta charset='utf-8'>"
IO.hPutStrLn handle "<title>2018 state of Haskell survey results</title>"
IO.hPutStrLn handle "</head>"
IO.hPutStrLn handle "<body>"
IO.hPutStrLn handle "<h1>2018 state of Haskell survey results</h1>"
fonts <- Diagrams.loadSansSerifFonts
let
options = Chart.set Diagrams.fo_fonts (pure fonts) Chart.def
makeBar = makeBarWith handle options responses
makeLikertBar = makeLikertBarWith handle options responses
makeMultipleBar = makeMultipleBarWith handle options responses
makeRatingBar = makeRatingBarWith handle options responses
makeSingleBar = makeSingleBarWith handle options responses
makeBar
(dateToDay . responseQ1)
1
"Submission date"
[ (Shown, "Nov 1", "2018-11-01", (<= Time.fromGregorian 2018 11 1))
, (Shown, "Nov 2", "2018-11-02", (== Time.fromGregorian 2018 11 2))
, (Shown, "Nov 3", "2018-11-03", (== Time.fromGregorian 2018 11 3))
, (Shown, "Nov 4", "2018-11-04", (== Time.fromGregorian 2018 11 4))
, (Shown, "Nov 5", "2018-11-05", (== Time.fromGregorian 2018 11 5))
, (Shown, "Nov 6", "2018-11-06", (== Time.fromGregorian 2018 11 6))
, (Shown, "Nov 7", "2018-11-07", (== Time.fromGregorian 2018 11 7))
, (Shown, "Nov 8", "2018-11-08", (== Time.fromGregorian 2018 11 8))
, (Shown, "Nov 9", "2018-11-09", (== Time.fromGregorian 2018 11 9))
, (Shown, "Nov 10", "2018-11-10", (== Time.fromGregorian 2018 11 10))
, (Shown, "Nov 11", "2018-11-11", (== Time.fromGregorian 2018 11 11))
, (Shown, "Nov 12", "2018-11-12", (== Time.fromGregorian 2018 11 12))
, (Shown, "Nov 13", "2018-11-13", (== Time.fromGregorian 2018 11 13))
, (Shown, "Nov 14", "2018-11-14", (>= Time.fromGregorian 2018 11 14))
]
makeRatingBar responseQ2 2 "Haskell usage"
makeSingleBar
responseQ3
3
"Do you use Haskell?"
[ (Shown, "Yes", "Yes")
, (Shown, "No, but I used to", "No, but I used to")
, (Shown, "No, I never have", "No, I never have")
]
makeSingleBar
responseQ4
4
"If you stopped using Haskell, how long did you use it before you stopped?"
[ (Shown, "Less than 1 day", "Less than 1 day")
, (Shown, "1 day to 1 week", "1 day to 1 week")
, (Shown, "1 week to 1 month", "1 week to 1 month")
, (Shown, "1 month to 1 year", "1 month to 1 year")
, (Shown, "More than 1 year", "More than 1 year")
]
makeMultipleBar
responseQ5
5
"If you do not use Haskell, why not?"
[ (Shown, "Company doesn't use", "My company doesn't use Haskell")
, (Shown, "Hard to learn", "Haskell is too hard to learn")
, ( Shown
, "Bad documentation"
, "Haskell's documentation is not good enough"
)
, (Shown, "Missing tooling", "Haskell lacks critical tools")
, (Shown, "Missing libraries", "Haskell lacks critical libraries")
, ( Hidden
, "Missing platforms"
, "Haskell does not support the platforms I need"
)
, (Hidden, "Bad performance", "Haskell's performance is not good enough")
, (Hidden, "Missing features", "Haskell lacks critical features")
]
makeSingleBar
responseQ7
7
"How long have you been using Haskell?"
[ (Shown, "<1d", "Less than 1 day")
, (Shown, "1d-1w", "1 day to 1 week")
, (Shown, "1w-1m", "1 week to 1 month")
, (Shown, "1m-1y", "1 month to 1 year")
, (Shown, "1y-2y", "1 year to 2 years")
, (Shown, "2y-3y", "2 years to 3 years")
, (Shown, "3y-4y", "3 years to 4 years")
, (Shown, "4y-5y", "4 years to 5 years")
, (Shown, ">5y", "More than 5 years")
]
makeSingleBar
responseQ8
8
"How frequently do you use Haskell?"
[ (Shown, "Daily", "Daily")
, (Shown, "Weekly", "Weekly")
, (Shown, "Monthly", "Monthly")
, (Shown, "Yearly", "Yearly")
, (Shown, "Rarely", "Rarely")
]
makeSingleBar
responseQ9
9
"How would you rate your proficiency in Haskell?"
[ (Shown, "Beginner", "Beginner")
, (Shown, "Intermediate", "Intermediate")
, (Shown, "Advanced", "Advanced")
, (Shown, "Expert", "Expert")
, (Shown, "Master", "Master")
]
makeMultipleBar
responseQ10
10
"Where do you use Haskell?"
[ (Shown, "Home", "Home")
, (Shown, "Work", "Work")
, (Shown, "School", "School")
]
makeSingleBar
responseQ11
11
"Do you use Haskell at work?"
[ (Shown, "Yes, most of the time", "Yes, most of the time")
, (Shown, "Yes, some of the time", "Yes, some of the time")
, (Shown, "No, but my company does", "No, but my company does")
, (Shown, "No", "No")
]
makeMultipleBar
responseQ12
12
"If you do not use Haskell at work, why not?"
[ (Shown, "Company doesn't use", "My company doesn't use Haskell")
, (Shown, "Hard to learn", "Haskell is too hard to learn")
, (Shown, "Hard to hire", "It is too hard to hire Haskell developers")
, (Shown, "Missing tooling", "Haskell lacks critical tools")
, ( Shown
, "Missing platforms"
, "Haskell does not support the platforms I need"
)
, (Hidden, "Missing libraries", "Haskell lacks critical libraries")
, (Hidden, "Bad performance", "Haskell's performance is not good enough")
, ( Hidden
, "Bad documentation"
, "Haskell's documentation is not good enough"
)
, (Hidden, "Missing features", "Haskell lacks critical features")
]
makeMultipleBar
responseQ14
14
"Which programming languages other than Haskell are you fluent in?"
$ fmap
(\(visibility, language) -> (visibility, language, language))
[ (Shown, "Java")
, (Shown, "Python")
, (Shown, "JavaScript")
, (Shown, "C")
, (Shown, "C++")
, (Shown, "Shell")
, (Shown, "Scala")
, (Shown, "Ruby")
, (Shown, "C#")
, (Shown, "TypeScript")
, (Hidden, "Rust")
, (Hidden, "PHP")
, (Hidden, "Assembly")
, (Hidden, "Go")
, (Hidden, "Clojure")
, (Hidden, "Ocaml")
, (Hidden, "Perl")
, (Hidden, "R")
, (Hidden, "Lua")
, (Hidden, "F#")
, (Hidden, "Erlang")
, (Hidden, "Matlab")
, (Hidden, "Objective-C")
, (Hidden, "Swift")
, (Hidden, "Kotlin")
, (Hidden, "Groovy")
, (Hidden, "VB.NET")
, (Hidden, "VBA")
, (Hidden, "Julia")
, (Hidden, "Hack")
]
makeMultipleBar
responseQ16
16
"Which types of software do you develop with Haskell?"
[ (Shown, "CLI", "Command-line programs (CLI)")
, (Shown, "Web (API)", "API services (returning non-HTML)")
, (Shown, "Data processing", "Data processing")
, (Shown, "Libraries", "Libraries or frameworks")
, (Shown, "Web (HTML)", "Web services (returning HTML)")
, (Shown, "Automation", "Automation or scripts")
, (Shown, "Daemon", "Agents or daemons")
, (Shown, "GUI", "Desktop programs (GUI)")
]
makeMultipleBar
responseQ18
18
"Which industries do you use Haskell in?"
[ (Shown, "Web", "Web")
, (Shown, "Finance", "Banking or finance")
, (Shown, "Education", "Education")
, (Shown, "Retail", "Commerce or retail")
, (Shown, "Government", "Government")
, (Shown, "Mobile", "Mobile")
, (Shown, "Health", "Healthcare or medical")
, (Shown, "Gaming", "Gaming")
, (Shown, "Embedded", "Embedded")
]
makeRatingBar responseQ20 20 "Projects"
makeSingleBar
responseQ21
21
"How many Haskell projects do you contribute to?"
[ (Shown, "0", "0")
, (Shown, "1", "1")
, (Shown, "2-5", "2 to 5")
, (Shown, "6-10", "6 to 10")
, (Shown, "11-20", "11 to 20")
, (Shown, ">20", "More than 20")
]
makeSingleBar
responseQ22
22
"What is the total size of all the Haskell projects you contribute to?"
[ (Shown, "<1k", "Less than 1,000 lines of code")
, (Shown, "1k-10k", "1,000 lines of code to 9,999 lines of code")
, (Shown, "10k-100k", "10,000 lines of code to 99,999 lines of code")
, (Shown, ">=100k", "100,000 or more lines of code")
]
makeMultipleBar
responseQ23
23
"Which platforms do you develop Haskell on?"
[ (Shown, "Linux", "Linux")
, (Shown, "MacOS", "MacOS")
, (Shown, "Windows", "Windows")
, (Shown, "BSD", "BSD")
]
makeMultipleBar
responseQ25
25
"Which platforms do you target?"
[ (Shown, "Linux", "Linux")
, (Shown, "MacOS", "MacOS")
, (Shown, "Windows", "Windows")
, (Shown, "BSD", "BSD")
, (Shown, "Android", "Android")
, (Shown, "iOS", "iOS")
]
makeRatingBar responseQ27 27 "Compilers"
makeMultipleBar
responseQ28
28
"Which Haskell compilers do you use?"
[(Shown, "GHC", "GHC"), (Shown, "GHCJS", "GHCJS"), (Shown, "Eta", "Eta")]
makeMultipleBar
responseQ30
30
"Which installation methods do you use for your Haskell compiler?"
[ (Shown, "Stack", "Stack")
, (Shown, "Nix", "Nix")
, (Shown, "OS", "Operating system package")
, (Shown, "Platform", "Haskell Platform")
, (Shown, "Binary", "Official binaries")
, (Shown, "Source", "Source")
, (Shown, "Minimal", "Minimal installer")
]
makeSingleBar
responseQ32
32
"Has upgrading your Haskell compiler broken your code in the last year?"
[(Shown, "Yes", "Yes"), (Shown, "No", "No")]
makeMultipleBar
responseQ33
33
"How has upgrading your Haskell compiler broken your code in the past year?"
[ ( Shown
, "Expected changes"
, "Expected changes, such as the MonadFail proposal"
)
, (Shown, "Incompatible deps", "Incompatible dependencies")
, (Shown, "Unexpected changes", "Unexpected changes")
, (Shown, "Compiler bugs", "Compiler bugs")
, (Shown, "New warnings", "New warnings")
]
makeBar
responseQ35
35
"Which versions of GHC do you use?"
[ (Hidden, "HEAD", "HEAD", contains "HEAD")
, (Shown, "8.6", "8.6.x", containsAny ["8.6.1"])
, (Shown, "8.4", "8.4.x", containsAny ["8.4.4", "8.4.3", "8.4.2", "8.4.1"])
, (Shown, "8.2", "8.2.x", containsAny ["8.2.1"])
, (Shown, "8.0", "8.0.x", containsAny ["8.0.2", "8.0.1"])
, (Shown, "7.10", "7.10.x", containsAny ["7.10.3", "7.10.2", "7.10.1"])
, (Shown, "7.8", "7.8.x", containsAny ["7.8.4", "7.8.3", "7.8.2", "7.8.1"])
, (Hidden, "7.6", "7.6.x", containsAny ["7.6.2", "7.6.1"])
, (Hidden, "7.4", "7.4.x", containsAny ["7.4.2", "7.4.1"])
, (Hidden, "7.2", "7.2.x", containsAny ["7.2.2", "7.2.1"])
, ( Hidden
, "7.0"
, "7.0.x"
, containsAny ["7.0.4", "7.0.3", "7.0.2", "7.0.1"]
)
]
makeSingleBar
responseQ36
36
"How do you feel about the new GHC release schedule?"
[ (Shown, "I like it", "I like it")
, (Shown, "I am indifferent", "I am indifferent")
, (Shown, "I dislike it", "I dislike it")
, (Shown, "I was not aware of it", "I was not aware of it")
]
makeMultipleBar
responseQ38
38
"Which GHC language extensions would you like to be enabled by default?"
[ (Shown, "OverloadedStrings", "OverloadedStrings")
, (Shown, "LambdaCase", "LambdaCase")
, (Shown, "DeriveFunctor", "DeriveFunctor")
, (Shown, "DeriveGeneric", "DeriveGeneric")
, (Shown, "BangPatterns", "BangPatterns")
, (Shown, "GADTs", "GADTs")
, (Hidden, "ScopedTypeVariables", "ScopedTypeVariables")
, (Hidden, "FlexibleInstances", "FlexibleInstances")
, (Hidden, "FlexibleContexts", "FlexibleContexts")
, (Hidden, "DeriveFoldable", "DeriveFoldable")
, (Hidden, "RankNTypes", "RankNTypes")
, (Hidden, "MultiParamTypeClasses", "MultiParamTypeClasses")
, (Hidden, "TupleSections", "TupleSections")
, (Hidden, "GeneralisedNewtypeDeriving", "GeneralisedNewtypeDeriving")
, (Hidden, "DeriveTraversable", "DeriveTraversable")
, (Hidden, "TypeApplications", "TypeApplications")
, (Hidden, "DataKinds", "DataKinds")
, (Hidden, "KindSignatures", "KindSignatures")
, (Hidden, "TypeOperators", "TypeOperators")
, (Hidden, "TypeFamilies", "TypeFamilies")
, (Hidden, "ApplicativeDo", "ApplicativeDo")
, (Hidden, "ViewPatterns", "ViewPatterns")
, (Hidden, "StandaloneDeriving", "StandaloneDeriving")
, (Hidden, "ConstraintKinds", "ConstraintKinds")
, (Hidden, "DerivingVia", "DerivingVia")
, (Hidden, "RecordWildCards", "RecordWildCards")
, (Hidden, "InstanceSigs", "InstanceSigs")
, (Hidden, "MultiWayIf", "MultiWayIf")
, (Hidden, "DeriveDataTypeable", "DeriveDataTypeable")
, (Hidden, "EmptyCase", "EmptyCase")
, (Hidden, "FunctionalDependencies", "FunctionalDependencies")
, (Hidden, "ExplicitForAll", "ExplicitForAll")
, (Hidden, "NamedFieldPuns", "NamedFieldPuns")
, (Hidden, "DerivingStrategies", "DerivingStrategies")
, (Hidden, "EmptyDataDecls", "EmptyDataDecls")
, (Hidden, "NumericUnderscores", "NumericUnderscores")
, (Hidden, "DeriveAnyClass", "DeriveAnyClass")
, (Hidden, "BinaryLiterals", "BinaryLiterals")
, (Hidden, "DefaultSignatures", "DefaultSignatures")
, (Hidden, "ExistentialQuantification", "ExistentialQuantification")
, (Hidden, "DuplicateRecordFields", "DuplicateRecordFields")
, (Hidden, "PatternSynonyms", "PatternSynonyms")
, (Hidden, "OverloadedLists", "OverloadedLists")
, (Hidden, "PolyKinds", "PolyKinds")
, (Hidden, "BlockArguments", "BlockArguments")
, (Hidden, "NoImplicitPrelude", "NoImplicitPrelude")
, (Hidden, "DeriveLift", "DeriveLift")
, (Hidden, "GADTSyntax", "GADTSyntax")
, (Hidden, "TypeSynonymInstances", "TypeSynonymInstances")
, (Hidden, "UnicodeSyntax", "UnicodeSyntax")
, (Hidden, "PatternGuards", "PatternGuards")
, (Hidden, "DisambiguateRecordFields", "DisambiguateRecordFields")
, (Hidden, "AutoDeriveTypeable", "AutoDeriveTypeable")
, (Hidden, "TypeInType", "TypeInType")
, (Hidden, "NoMonomorphismRestriction", "NoMonomorphismRestriction")
, (Hidden, "PartialTypeSignatures", "PartialTypeSignatures")
, (Hidden, "TypeFamilyDependencies", "TypeFamilyDependencies")
, (Hidden, "Arrows", "Arrows")
, (Hidden, "TemplateHaskell", "TemplateHaskell")
, (Hidden, "PackageImports", "PackageImports")
, (Hidden, "NamedWildCards", "NamedWildCards")
, (Hidden, "QuasiQuotes", "QuasiQuotes")
, (Hidden, "QuantifiedConstraints", "QuantifiedConstraints")
, (Hidden, "NegativeLiterals", "NegativeLiterals")
, (Hidden, "MonadComprehensions", "MonadComprehensions")
, (Hidden, "ParallelListComp", "ParallelListComp")
, (Hidden, "AllowAmbiguousTypes", "AllowAmbiguousTypes")
, (Hidden, "RecordPuns", "RecordPuns")
, (Hidden, "DoAndIfThenElse", "DoAndIfThenElse")
, (Hidden, "EmptyDataDeriving", "EmptyDataDeriving")
, (Hidden, "RecursiveDo", "RecursiveDo")
, (Hidden, "PatternSignatures", "PatternSignatures")
, (Hidden, "StarIsType", "StarIsType")
, (Hidden, "MagicHash", "MagicHash")
, (Hidden, "ForeignFunctionInterface", "ForeignFunctionInterface")
, (Hidden, "MonadFailDesugaring", "MonadFailDesugaring")
, (Hidden, "RoleAnnotations", "RoleAnnotations")
, (Hidden, "Rank2Types", "Rank2Types")
, (Hidden, "StrictData", "StrictData")
, (Hidden, "NumDecimals", "NumDecimals")
, (Hidden, "OverloadedLabels", "OverloadedLabels")
, (Hidden, "IncoherentInstances", "IncoherentInstances")
, (Hidden, "NullaryTypeClasses", "NullaryTypeClasses")
, (Hidden, "ImplicitParams", "ImplicitParams")
, (Hidden, "ConstrainedClassMethods", "ConstrainedClassMethods")
, (Hidden, "LiberalTypeSynonyms", "LiberalTypeSynonyms")
, (Hidden, "CPP", "CPP")
, (Hidden, "UndecidableInstances", "UndecidableInstances")
, (Hidden, "UnboxedTuples", "UnboxedTuples")
, (Hidden, "ExplicitNamespaces", "ExplicitNamespaces")
, (Hidden, "UnboxedSums", "UnboxedSums")
, (Hidden, "HexFloatLiterals", "HexFloatLiterals")
, (Hidden, "DoRec", "DoRec")
, (Hidden, "Strict", "Strict")
, (Hidden, "TransformListComp", "TransformListComp")
, (Hidden, "OverlappingInstances", "OverlappingInstances")
, (Hidden, "ParallelArrays", "ParallelArrays")
, (Hidden, "ExtendedDefaultRules", "ExtendedDefaultRules")
, (Hidden, "PostfixOperators", "PostfixOperators")
, (Hidden, "AlternativeLayoutRule", "AlternativeLayoutRule")
, (Hidden, "DatatypeContexts", "DatatypeContexts")
, (Hidden, "TemplateHaskellQuotes", "TemplateHaskellQuotes")
, (Hidden, "NPlusKPatterns", "NPlusKPatterns")
, (Hidden, "ImpredicativeTypes", "ImpredicativeTypes")
, (Hidden, "CApiFFI", "CApiFFI")
, (Hidden, "NoTraditionalRecordSyntax", "NoTraditionalRecordSyntax")
, (Hidden, "PolymorphicComponents", "PolymorphicComponents")
, (Hidden, "RebindableSyntax", "RebindableSyntax")
, (Hidden, "UnliftedFFITypes", "UnliftedFFITypes")
, ( Hidden
, "AlternativeLayoutRuleTransitional"
, "AlternativeLayoutRuleTransitional"
)
, (Hidden, "InterruptibleFFI", "InterruptibleFFI")
, (Hidden, "UndecidableSuperClasses", "UndecidableSuperClasses")
, (Hidden, "MonoLocalBinds", "MonoLocalBinds")
, (Hidden, "MonoPatBinds", "MonoPatBinds")
, (Hidden, "JavaScriptFFI", "JavaScriptFFI")
, (Hidden, "RelaxedPolyRec", "RelaxedPolyRec")
, (Hidden, "RelaxedLayout", "RelaxedLayout")
, (Hidden, "StaticPointers", "StaticPointers")
, (Hidden, "GHCForeignImportPrim", "GHCForeignImportPrim")
]
makeSingleBar
responseQ39
39
"How important do you feel it would be to have a new version of the Haskell standard?"
[ (Shown, "Not at all", "Not at all important")
, (Shown, "Slightly", "Slightly important")
, (Shown, "Moderately", "Moderately important")
, (Shown, "Very", "Very important")
, (Shown, "Extremely", "Extremely important")
]
makeRatingBar responseQ40 40 "Tooling"
makeMultipleBar
responseQ41
41
"Which build tools do you use for Haskell?"
[ (Shown, "Stack", "Stack")
, (Shown, "Cabal", "Cabal")
, (Shown, "Nix", "Nix")
, (Shown, "Make", "Make")
, (Shown, "Shake", "Shake")
, (Shown, "ghc-pkg", "ghc-pkg")
, (Shown, "Bazel", "Bazel")
, (Shown, "Mafia", "Mafia")
]
makeMultipleBar
responseQ43
43
"Which editors do you use for Haskell?"
[ (Shown, "Emacs", "Emacs")
, (Shown, "Vi", "Vi")
, (Shown, "VSCode", "Visual Studio Code")
, (Shown, "Atom", "Atom")
, (Shown, "Sublime Text", "Sublime Text")
, (Shown, "Notepad++", "Notepad++")
, (Shown, "IntelliJ IDEA", "IntelliJ IDEA")
]
makeMultipleBar
responseQ45
45
"Which version control systems do you use for Haskell?"
[ (Shown, "Git", "Git")
, (Shown, "Darcs", "Darcs")
, (Shown, "Mercurial", "Mercurial")
, (Shown, "Subversion", "Subversion")
, (Shown, "Pijul", "Pijul")
, (Shown, "Fossil", "Fossil")
]
makeMultipleBar
responseQ47
47
"Where do you get Haskell packages from?"
[ (Shown, "Stackage", "Stackage")
, (Shown, "Hackage", "Hackage")
, (Shown, "Source", "Source")
, (Shown, "Nix", "Nix")
]
makeMultipleBar
responseQ49
49
"Which libraries do you use to test Haskell code?"
[ (Shown, "QuickCheck", "QuickCheck")
, (Shown, "Hspec", "Hspec")
, (Shown, "Tasty", "Tasty")
, (Shown, "HUnit", "HUnit")
, (Shown, "Hedgehog", "Hedgehog")
, (Shown, "HTF", "Haskell Test Framework")
, (Shown, "SmallCheck", "SmallCheck")
, (Shown, "LeanCheck", "LeanCheck")
]
makeMultipleBar
responseQ51
51
"Which libraries do you use to benchmark Haskell code?"
[ (Shown, "Criterion", "Criterion")
, (Shown, "Bench", "Bench")
, (Shown, "Gauge", "Gauge")
]
makeRatingBar responseQ53 53 "Infrastructure"
makeMultipleBar
responseQ54
54
"Which tools do you use to deploy Haskell applications?"
[ (Shown, "Static binaries", "Static binaries")
, (Shown, "Docker images", "Docker images")
, (Shown, "Dynamic binaries", "Dynamic binaries")
, (Shown, "Nix expressions", "Nix expressions")
]
makeMultipleBar
responseQ56
56
"Where do you deploy Haskell applications?"
[ (Shown, "Own servers", "Self or company owned servers")
, (Shown, "AWS", "Amazon Web Services (AWS)")
, (Shown, "Google Cloud", "Google Cloud")
, (Shown, "Digital Ocean", "Digital Ocean")
, (Shown, "Heroku", "Heroku")
, (Shown, "Azure", "Microsoft Azure")
]
makeRatingBar responseQ58 58 "Community"
makeMultipleBar
responseQ59
59
"Where do you interact with the Haskell community?"
[ (Shown, "Reddit", "Reddit")
, (Shown, "GitHub", "GitHub")
, (Shown, "Twitter", "Twitter")
, (Shown, "IRC", "IRC")
, (Shown, "Mailing lists", "Mailing lists")
, (Shown, "Meetups", "Meetups")
, (Shown, "Stack Overflow", "Stack Overflow")
, (Shown, "Slack", "Slack")
, (Hidden, "Commerical conferences", "Conferences (commercial)")
, (Hidden, "Academic conferences", "Conferences (academic)")
, (Hidden, "Discord", "Discord")
, (Hidden, "Gitter", "Gitter")
, (Hidden, "Matrix/Riot", "Matrix/Riot")
, (Hidden, "Lobsters", "Lobsters")
, (Hidden, "Telegram", "Telegram")
, (Hidden, "Mastodon", "Mastodon")
]
makeMultipleBar
responseQ61
61
"Which of the following Haskell topics would you like to see more written about?"
[ (Shown, "Best practices", "Best practices")
, (Shown, "Patterns", "Design patterns")
, (Shown, "Architecture", "Application architectures")
, (Shown, "Performance", "Performance analysis")
, (Shown, "Libraries", "Library walkthroughs")
, (Shown, "Tooling", "Tooling choices")
, (Shown, "Debugging", "Debugging how-tos")
, (Shown, "Infrastructure", "Production infrastructure")
, (Hidden, "Case studies", "Case studies")
, (Hidden, "Web development", "Web development")
, (Hidden, "Algorithm implementations", "Algorithm implementations")
, (Hidden, "GUIs", "GUIs")
, (Hidden, "Beginner fundamentals", "Beginner fundamentals")
, (Hidden, "Machine learning", "Machine learning")
, (Hidden, "Project setup", "Project setup")
, (Hidden, "Project maintenance", "Project maintenance")
, (Hidden, "Game development", "Game development")
, (Hidden, "Mobile development", "Mobile development")
, ( Hidden
, "Comparisons to other languages"
, "Comparisons to other languages"
)
]
makeRatingBar responseQ63 63 "Feelings"
makeLikertBar responseQ64 64 "I feel welcome in the Haskell community."
makeLikertBar responseQ65 65 "I am satisfied with Haskell as a language."
makeLikertBar
responseQ67
67
"I am satisfied with Haskell's compilers, such as GHC."
makeLikertBar
responseQ69
69
"I am satisfied with Haskell's build tools, such as Cabal."
makeLikertBar
responseQ71
71
"I am satisfied with Haskell's package repositories, such as Hackage."
makeLikertBar
responseQ73
73
"I can find Haskell libraries for the things that I need."
makeLikertBar responseQ74 74 "I think Haskell libraries are high quality."
makeLikertBar
responseQ75
75
"I have a good understanding of Haskell best practices."
makeLikertBar responseQ76 76 "I think Haskell libraries are well documented."
makeLikertBar
responseQ77
77
"I can easily compare competing Haskell libraries to select the best one."
makeLikertBar
responseQ78
78
"I think that Haskell libraries are easy to use."
makeLikertBar
responseQ79
79
"I think that Haskell libraries provide a stable API."
makeLikertBar
responseQ80
80
"I think that Haskell libraries work well together."
makeLikertBar
responseQ81
81
"I think that software written in Haskell is easy to maintain."
makeLikertBar
responseQ82
82
"Once my Haskell program compiles, it generally does what I intended."
makeLikertBar responseQ83 83 "I think that Haskell libraries perform well."
makeLikertBar responseQ84 84 "Haskell's performance meets my needs."
makeLikertBar
responseQ85
85
"I can easily reason about the performance of my Haskell code."
makeLikertBar responseQ86 86 "I would recommend using Haskell to others."
makeLikertBar
responseQ87
87
"I would prefer to use Haskell for my next new project."
makeLikertBar responseQ88 88 "Haskell is working well for my team."
makeLikertBar responseQ89 89 "Haskell is critical to my company's success."
makeLikertBar
responseQ90
90
"As a candidate, I can easily find Haskell jobs."
makeLikertBar
responseQ91
91
"As a hiring manager, I can easily find qualified Haskell candidates."
makeRatingBar responseQ94 94 "Demographics"
makeSingleBar responseQ95 95 "Which country do you live in?" $ fmap
(\(visibility, country) -> (visibility, country, country))
[ (Shown, "United States")
, (Shown, "United Kingdom")
, (Shown, "Germany")
, (Shown, "Australia")
, (Shown, "France")
, (Hidden, "Russia")
, (Hidden, "Canada")
, (Hidden, "Sweden")
, (Hidden, "Netherlands")
, (Hidden, "India")
, (Hidden, "Japan")
, (Hidden, "Italy")
, (Hidden, "Finland")
, (Hidden, "Poland")
, (Hidden, "Switzerland")
, (Hidden, "Austria")
, (Hidden, "Norway")
, (Hidden, "Czechia")
, (Hidden, "Denmark")
, (Hidden, "Belgium")
, (Hidden, "Spain")
, (Hidden, "New Zealand")
, (Hidden, "Brazil")
, (Hidden, "China")
, (Hidden, "Ireland")
, (Hidden, "Israel")
, (Hidden, "Ukraine")
, (Hidden, "Portugal")
, (Hidden, "Croatia")
, (Hidden, "Belarus")
, (Hidden, "Romania")
, (Hidden, "Argentina")
, (Hidden, "Bulgaria")
, (Hidden, "Greece")
, (Hidden, "Indonesia")
, (Hidden, "Latvia")
, (Hidden, "South Africa")
, (Hidden, "Turkey")
, (Hidden, "Ecuador")
, (Hidden, "Estonia")
, (Hidden, "Hungary")
, (Hidden, "Kenya")
, (Hidden, "Singapore")
, (Hidden, "Mexico")
, (Hidden, "Thailand")
, (Hidden, "Algeria")
, (Hidden, "Armenia")
, (Hidden, "Azerbaijan")
, (Hidden, "Bolivia")
, (Hidden, "Cameroon")
, (Hidden, "Chile")
, (Hidden, "Colombia")
, (Hidden, "Egypt")
, (Hidden, "Guatemala")
, (Hidden, "Iceland")
, (Hidden, "Iran")
, (Hidden, "Kazakhstan")
, (Hidden, "Lebanon")
, (Hidden, "Malta")
, (Hidden, "Nepal")
, (Hidden, "Nigeria")
, (Hidden, "Pakistan")
, (Hidden, "Paraguay")
, (Hidden, "Peru")
, (Hidden, "Philippines")
, (Hidden, "Serbia")
, (Hidden, "Slovakia")
, (Hidden, "Slovenia")
, (Hidden, "South Korea")
, (Hidden, "Syria")
, (Hidden, "Uganda")
, (Hidden, "Vietnam")
]
makeSingleBar
responseQ96
96
"How old are you?"
[ (Shown, "<18", "Under 18 years old")
, (Shown, "18-24", "18 to 24 years old")
, (Shown, "25-34", "25 to 34 years old")
, (Shown, "35-44", "35 to 44 years old")
, (Shown, "45-54", "45 to 54 years old")
, (Shown, "55-64", "55 to 64 years old")
, (Shown, ">=65", "65 years or older")
]
makeSingleBar
responseQ97
97
"What is your gender?"
[ (Shown, "Male", "Male")
, (Shown, "Female", "Female")
, (Shown, "Non-binary", "Non-binary")
]
makeSingleBar
responseQ98
98
"Do you identify as transgender?"
[(Shown, "No", "No"), (Shown, "Yes", "Yes")]
makeSingleBar
responseQ99
99
"Are you a student?"
[ (Shown, "No", "No")
, (Shown, "Yes, full time", "Yes, full time")
, (Shown, "Yes, part time", "Yes, part time")
]
makeSingleBar
responseQ100
100
"What is the highest level of education you have completed?"
[ ( Hidden
, "Less than high school diploma"
, "Less than high school diploma"
)
, (Shown, "High school", "High school diploma")
, (Shown, "Some college", "Some college")
, (Shown, "Associate", "Associate degree")
, (Shown, "Bachelor's", "Bachelor's degree")
, (Shown, "Master's", "Master's degree")
, (Shown, "Professional", "Professional degree")
, (Shown, "Doctoral", "Doctoral degree")
]
makeSingleBar
responseQ101
101
"What is your employment status?"
[ (Shown, "Full time", "Employed full time")
, (Shown, "Self employed", "Self employed")
, (Shown, "Part time", "Employed part time")
, (Shown, "Looking", "Not employed, but looking for work")
, (Shown, "Not looking", "Not employed, and not looking for work")
, (Shown, "Retired", "Retired")
]
makeSingleBar
responseQ102
102
"How large is the company you work for?"
[ (Shown, "<10", "Fewer than 10 employees")
, (Shown, "10-99", "10 to 99 employees")
, (Shown, "100-999", "100 to 999 employees")
, (Shown, ">=1000", "1,000 or more employees")
]
makeSingleBar
responseQ103
103
"How many years have you been coding?"
[ (Shown, "<5", "0 to 4 years")
, (Shown, "5-9", "5 to 9 years")
, (Shown, "10-14", "10 to 14 years")
, (Shown, "15-19", "15 to 19 years")
, (Shown, "20-24", "20 to 24 years")
, (Shown, "25-29", "25 to 29 years")
, (Shown, ">=30", "30 or more years")
]
makeSingleBar
responseQ104
104
"How many years have you been coding professionally?"
[ (Shown, "<5", "0 to 4 years")
, (Shown, "5-9", "5 to 9 years")
, (Shown, "10-19", "10 to 19 years")
, (Shown, "20-29", "20 to 29 years")
, (Shown, ">=30", "30 or more years")
]
makeSingleBar
responseQ105
105
"Do you code as a hobby?"
[(Shown, "Yes", "Yes"), (Shown, "No", "No")]
makeSingleBar
responseQ106
106
"Have you contributed to any open source projects?"
[(Shown, "Yes", "Yes"), (Shown, "No", "No")]
makeRatingBar responseQ107 107 "Meta survey"
makeSingleBar
responseQ108
108
"Did you take last year's survey?"
[ (Shown, "No", "No")
, (Shown, "Yes", "Yes")
, (Shown, "Not sure", "I don't remember")
]
makeSingleBar
responseQ109
109
"How did you hear about this survey?"
[ (Shown, "Reddit", "Reddit")
, (Shown, "Twitter", "Twitter")
, (Shown, "Haskell Weekly", "Haskell Weekly")
, (Shown, "Mailing list", "Mailing list")
, (Shown, "Other", "Other")
, (Shown, "In person", "In person")
, (Shown, "Lobsters", "Lobsters")
, (Shown, "Slack", "Slack")
, (Hidden, "Discord", "Discord")
, (Hidden, "IRC", "IRC")
, (Hidden, "Matrix/Riot", "Matrix/Riot")
, (Hidden, "Telegram", "Telegram")
, (Hidden, "Gitter", "Gitter")
, (Hidden, "Mastodon", "Mastodon")
]
IO.hPutStrLn handle "</body>"
IO.hPutStrLn handle "</html>"
IO.hFlush handle
data Response = Response
{ responseQ1 :: Date
-- ^ Submission date
, responseQ2 :: Maybe Int
-- ^ HASKELL USAGE
, responseQ3 :: Maybe Text.Text
-- ^ Do you use Haskell?
, responseQ4 :: Maybe Text.Text
-- ^ If you stopped using Haskell, how long did you use it before you stopped?
, responseQ5 :: Multiple Text.Text
-- ^ If you do not use Haskell, why not?
, responseQ7 :: Maybe Text.Text
-- ^ How long have you been using Haskell?
, responseQ8 :: Maybe Text.Text
-- ^ How frequently do you use Haskell?
, responseQ9 :: Maybe Text.Text
-- ^ How would you rate your proficiency in Haskell?
, responseQ10 :: Multiple Text.Text
-- ^ Where do you use Haskell?
, responseQ11 :: Maybe Text.Text
-- ^ Do you use Haskell at work?
, responseQ12 :: Multiple Text.Text
-- ^ If you do not use Haskell at work, why not?
, responseQ14 :: Multiple Text.Text
-- ^ Which programming languages other than Haskell are you fluent in?
, responseQ16 :: Multiple Text.Text
-- ^ Which types of software do you develop with Haskell?
, responseQ18 :: Multiple Text.Text
-- ^ Which industries do you use Haskell in?
, responseQ20 :: Maybe Int
-- ^ PROJECTS
, responseQ21 :: Maybe Text.Text
-- ^ How many Haskell projects do you contribute to?
, responseQ22 :: Maybe Text.Text
-- ^ What is the total size of all the Haskell projects you contribute to?
, responseQ23 :: Multiple Text.Text
-- ^ Which platforms do you develop Haskell on?
, responseQ25 :: Multiple Text.Text
-- ^ Which platforms do you target?
, responseQ27 :: Maybe Int
-- ^ COMPILERS
, responseQ28 :: Multiple Text.Text
-- ^ Which Haskell compilers do you use?
, responseQ30 :: Multiple Text.Text
-- ^ Which installation methods do you use for your Haskell compiler?
, responseQ32 :: Maybe Text.Text
-- ^ Has upgrading your Haskell compiler broken your code in the last year?
, responseQ33 :: Multiple Text.Text
-- ^ How has upgrading your Haskell compiler broken your code in the past year?
, responseQ35 :: Multiple Text.Text
-- ^ Which versions of GHC do you use?
, responseQ36 :: Maybe Text.Text
-- ^ How do you feel about the new GHC release schedule?
, responseQ38 :: Multiple Text.Text
-- ^ Which GHC language extensions would you like to be enabled by default?
, responseQ39 :: Maybe Text.Text
-- ^ How important do you feel it would be to have a new version of the Haskell standard?
, responseQ40 :: Maybe Int
-- ^ TOOLING
, responseQ41 :: Multiple Text.Text
-- ^ Which build tools do you use for Haskell?
, responseQ43 :: Multiple Text.Text
-- ^ Which editors do you use for Haskell?
, responseQ45 :: Multiple Text.Text
-- ^ Which version control systems do you use for Haskell?
, responseQ47 :: Multiple Text.Text
-- ^ Where do you get Haskell packages from?
, responseQ49 :: Multiple Text.Text
-- ^ Which libraries do you use to test Haskell code?
, responseQ51 :: Multiple Text.Text
-- ^ Which libraries do you use to benchmark Haskell code?
, responseQ53 :: Maybe Int
-- ^ INFRASTRUCTURE
, responseQ54 :: Multiple Text.Text
-- ^ Which tools do you use to deploy Haskell applications?
, responseQ56 :: Multiple Text.Text
-- ^ Where do you deploy Haskell applications?
, responseQ58 :: Maybe Int
-- ^ COMMUNITY
, responseQ59 :: Multiple Text.Text
-- ^ Where do you interact with the Haskell community?
, responseQ61 :: Multiple Text.Text
-- ^ Which of the following Haskell topics would you like to see more written about?
, responseQ63 :: Maybe Int
-- ^ FEELINGS
, responseQ64 :: Maybe Text.Text
-- ^ I feel welcome in the Haskell community.
, responseQ65 :: Maybe Text.Text
-- ^ I am satisfied with Haskell as a language.
, responseQ67 :: Maybe Text.Text
-- ^ I am satisfied with Haskell's compilers, such as GHC.
, responseQ69 :: Maybe Text.Text
-- ^ I am satisfied with Haskell's build tools, such as Cabal.
, responseQ71 :: Maybe Text.Text
-- ^ I am satisfied with Haskell's package repositories, such as Hackage.
, responseQ73 :: Maybe Text.Text
-- ^ I can find Haskell libraries for the things that I need.
, responseQ74 :: Maybe Text.Text
-- ^ I think Haskell libraries are high quality.
, responseQ75 :: Maybe Text.Text
-- ^ I have a good understanding of Haskell best practices.
, responseQ76 :: Maybe Text.Text
-- ^ I think Haskell libraries are well documented.
, responseQ77 :: Maybe Text.Text
-- ^ I can easily compare competing Haskell libraries to select the best one.
, responseQ78 :: Maybe Text.Text
-- ^ I think that Haskell libraries are easy to use.
, responseQ79 :: Maybe Text.Text
-- ^ I think that Haskell libraries provide a stable API.
, responseQ80 :: Maybe Text.Text
-- ^ I think that Haskell libraries work well together.
, responseQ81 :: Maybe Text.Text
-- ^ I think that software written in Haskell is easy to maintain.
, responseQ82 :: Maybe Text.Text
-- ^ Once my Haskell program compiles, it generally does what I intended.
, responseQ83 :: Maybe Text.Text
-- ^ I think that Haskell libraries perform well.
, responseQ84 :: Maybe Text.Text
-- ^ Haskell's performance meets my needs.
, responseQ85 :: Maybe Text.Text
-- ^ I can easily reason about the performance of my Haskell code.
, responseQ86 :: Maybe Text.Text
-- ^ I would recommend using Haskell to others.
, responseQ87 :: Maybe Text.Text
-- ^ I would prefer to use Haskell for my next new project.
, responseQ88 :: Maybe Text.Text
-- ^ Haskell is working well for my team.
, responseQ89 :: Maybe Text.Text
-- ^ Haskell is critical to my company's success.
, responseQ90 :: Maybe Text.Text
-- ^ As a candidate, I can easily find Haskell jobs.
, responseQ91 :: Maybe Text.Text
-- ^ As a hiring manager, I can easily find qualified Haskell candidates.
, responseQ94 :: Maybe Int
-- ^ DEMOGRAPHICS
, responseQ95 :: Maybe Text.Text
-- ^ Which country do you live in?
, responseQ96 :: Maybe Text.Text
-- ^ How old are you?
, responseQ97 :: Maybe Text.Text
-- ^ What is your gender?
, responseQ98 :: Maybe Text.Text
-- ^ Do you identify as transgender?
, responseQ99 :: Maybe Text.Text
-- ^ Are you a student?
, responseQ100 :: Maybe Text.Text
-- ^ What is the highest level of education you have completed?
, responseQ101 :: Maybe Text.Text
-- ^ What is your employment status?
, responseQ102 :: Maybe Text.Text
-- ^ How large is the company you work for?
, responseQ103 :: Maybe Text.Text
-- ^ How many years have you been coding?
, responseQ104 :: Maybe Text.Text
-- ^ How many years have you been coding professionally?
, responseQ105 :: Maybe Text.Text
-- ^ Do you code as a hobby?
, responseQ106 :: Maybe Text.Text
-- ^ Have you contributed to any open source projects?
, responseQ107 :: Maybe Int
-- ^ META SURVEY
, responseQ108 :: Maybe Text.Text
-- ^ Did you take last year's survey?
, responseQ109 :: Maybe Text.Text
-- ^ How did you hear about this survey?
, responseQ110 :: Maybe Text.Text
-- ^ Do you have any feedback about the survey itself?
}
instance Csv.FromRecord Response where
parseRecord record = Response
<$> Csv.index record 1
<*> Csv.index record 2
<*> Csv.index record 3
<*> Csv.index record 4
<*> Csv.index record 5
<*> Csv.index record 7
<*> Csv.index record 8
<*> Csv.index record 9
<*> Csv.index record 10
<*> Csv.index record 11
<*> Csv.index record 12
<*> Csv.index record 14
<*> Csv.index record 16
<*> Csv.index record 18
<*> Csv.index record 20
<*> Csv.index record 21
<*> Csv.index record 22
<*> Csv.index record 23
<*> Csv.index record 25
<*> Csv.index record 27
<*> Csv.index record 28
<*> Csv.index record 30
<*> Csv.index record 32
<*> Csv.index record 33
<*> Csv.index record 35
<*> Csv.index record 36
<*> Csv.index record 38
<*> Csv.index record 39
<*> Csv.index record 40
<*> Csv.index record 41
<*> Csv.index record 43
<*> Csv.index record 45
<*> Csv.index record 47
<*> Csv.index record 49
<*> Csv.index record 51
<*> Csv.index record 53
<*> Csv.index record 54
<*> Csv.index record 56
<*> Csv.index record 58
<*> Csv.index record 59
<*> Csv.index record 61
<*> Csv.index record 63
<*> Csv.index record 64
<*> Csv.index record 65
<*> Csv.index record 67
<*> Csv.index record 69
<*> Csv.index record 71
<*> Csv.index record 73
<*> Csv.index record 74
<*> Csv.index record 75
<*> Csv.index record 76
<*> Csv.index record 77
<*> Csv.index record 78
<*> Csv.index record 79
<*> Csv.index record 80
<*> Csv.index record 81
<*> Csv.index record 82
<*> Csv.index record 83
<*> Csv.index record 84
<*> Csv.index record 85
<*> Csv.index record 86
<*> Csv.index record 87
<*> Csv.index record 88
<*> Csv.index record 89
<*> Csv.index record 90
<*> Csv.index record 91
<*> Csv.index record 94
<*> Csv.index record 95
<*> Csv.index record 96
<*> Csv.index record 97
<*> Csv.index record 98
<*> Csv.index record 99
<*> Csv.index record 100
<*> Csv.index record 101
<*> Csv.index record 102
<*> Csv.index record 103
<*> Csv.index record 104
<*> Csv.index record 105
<*> Csv.index record 106
<*> Csv.index record 107
<*> Csv.index record 108
<*> Csv.index record 109
<*> Csv.index record 110
newtype Date
= Date Time.Day
instance Csv.FromField Date where
parseField field = do
string <- Csv.parseField field
Date <$> Time.parseTimeM False Time.defaultTimeLocale "%Y-%m-%d" string
dateToDay :: Date -> Time.Day
dateToDay (Date day) = day
newtype Multiple a
= Multiple (Set.Set a)
instance (Csv.FromField a, Ord a) => Csv.FromField (Multiple a) where
parseField field = do
records <-
either fail pure . Csv.decode Csv.NoHeader $ LazyByteString.fromStrict
field
record <- case Vector.toList records of
[] -> pure Vector.empty
[record] -> pure record
_ -> fail $ "too many records: " ++ show records
Multiple . Set.fromList . Vector.toList <$> traverse Csv.parseField record
multipleToSet :: Multiple a -> Set.Set a
multipleToSet (Multiple set) = set
data Visibility
= Hidden
| Shown
contains :: String -> Multiple Text.Text -> Bool
contains = containsAny . pure
containsAny :: [String] -> Multiple Text.Text -> Bool
containsAny xs ys = any (\x -> Set.member (Text.pack x) (multipleToSet ys)) xs
count :: (a -> Bool) -> Vector.Vector a -> Int
count predicate = Vector.foldr
(\element total -> if predicate element then total + 1 else total)
0
escape :: String -> String
escape = concatMap escapeChar
escapeChar :: Char -> String
escapeChar c = case c of
'\'' -> "&apos;"
'"' -> "&quot;"
'&' -> "&amp;"
'<' -> "&lt;"
'>' -> "&gt;"
_ -> [c]
is :: String -> Maybe Text.Text -> Bool
is string field = field == Just (Text.pack string)
makeBarWith
:: IO.Handle
-> Diagrams.FileOptions
-> Vector.Vector Response
-> (Response -> a)
-> Int
-> String
-> [(Visibility, String, String, a -> Bool)]
-> IO ()
makeBarWith handle options responses getField number title bins = do
let
path = FilePath.combine outputDirectory
$ FilePath.addExtension (Printf.printf "question-%03d" number) "svg"
fields = fmap getField responses
bars = fmap (\(v, s, l, p) -> (v, s, l, count p fields)) bins
Printf.printf "- [%s](#question-%03d)\n" title number
let total = fromIntegral $ Vector.length responses :: Double
IO.hPutStr handle $ Printf.printf "<h2 id='question-%03d'>" number
IO.hPutStr handle $ Printf.printf "<a href='#question-%03d'>#</a> " number
IO.hPutStr handle $ escape title
IO.hPutStr handle " <a href='#'>^</a>"
IO.hPutStrLn handle "</h2>"
IO.hPutStr handle $ Printf.printf "<a href='question-%03d.svg'>" number
IO.hPutStr handle
. uncurry
(Printf.printf
"<img src='question-%03d.svg' alt='' width='%f' height='%f'>"
number
)
$ Chart.view Diagrams.fo_size options
IO.hPutStrLn handle "</a>"
IO.hPutStrLn handle "<table>"
IO.hPutStrLn handle "<thead>"
IO.hPutStr handle "<tr>"
IO.hPutStr handle "<th>Answer</th>"
IO.hPutStr handle "<th>Count</th>"
IO.hPutStr handle "<th>Percent</th>"
IO.hPutStr handle "</tr>"
IO.hPutStrLn handle "</thead>"
IO.hPutStrLn handle "<tbody>"
Monad.forM_ bars $ \(_, _, l, c) -> do
IO.hPutStr handle "<tr>"
IO.hPutStr handle . Printf.printf "<td>%s</td>" $ escape l
IO.hPutStr handle $ Printf.printf "<td>%d</td>" c
IO.hPutStr handle
. Printf.printf "<td>%.1f%%</td>"
$ 100
* fromIntegral c
/ total
IO.hPutStrLn handle "</tr>"
IO.hPutStrLn handle "</tbody>"
IO.hPutStrLn handle "</table>"
Diagrams.toFile options path $ do
Chart.assign Chart.layout_title title
Chart.setColors . pure . Chart.opaque $ Color.sRGB24 0x5c 0x35 0x66
Chart.assign (Chart.layout_x_axis . Chart.laxis_generate)
. Chart.autoIndexAxis
$ Maybe.mapMaybe
(\(v, s, _, _) -> case v of
Hidden -> Nothing
Shown -> Just s
)
bars
Chart.plot
. fmap Chart.plotBars
. Chart.bars [""]
. Chart.addIndexes
. fmap pure
$ Maybe.mapMaybe
(\(v, _, _, c) -> case v of
Hidden -> Nothing
Shown -> Just c
)
bars
makeLikertBarWith
:: IO.Handle
-> Diagrams.FileOptions
-> Vector.Vector Response
-> (Response -> Maybe Text.Text)
-> Int
-> String
-> IO ()
makeLikertBarWith handle options responses getField number title =
makeBarWith handle options responses getField number title $ fmap
(\x -> (Shown, x, x, is x))
["Strongly disagree", "Disagree", "Neutral", "Agree", "Strongly agree"]
makeMultipleBarWith
:: IO.Handle
-> Diagrams.FileOptions
-> Vector.Vector Response
-> (Response -> Multiple Text.Text)
-> Int
-> String
-> [(Visibility, String, String)]
-> IO ()
makeMultipleBarWith handle options responses getField number title =
makeBarWith
handle
options
responses
getField
number
(Printf.printf "%s (multiple select)" title)
. fmap
(\(visibility, name, value) ->
(visibility, name, value, contains value)
)
makeRatingBarWith
:: IO.Handle
-> Diagrams.FileOptions
-> Vector.Vector Response
-> (Response -> Maybe Int)
-> Int
-> String
-> IO ()
makeRatingBarWith handle options responses getField number title =
makeBarWith handle options responses getField number title $ fmap
(\n ->
( Shown
, show n
, Printf.printf "%d heart%s" n (if n == 1 then "" else "s")
, (== Just n)
)
)
[1 .. 10]
makeSingleBarWith
:: IO.Handle
-> Diagrams.FileOptions
-> Vector.Vector Response
-> (Response -> Maybe Text.Text)
-> Int
-> String
-> [(Visibility, String, String)]
-> IO ()
makeSingleBarWith handle options responses getField number title =
makeBarWith
handle
options
responses
getField
number
(Printf.printf "%s (single select)" title)
. fmap (\(visibility, name, value) -> (visibility, name, value, is value))
outputDirectory :: FilePath
outputDirectory = "output"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment