Skip to content

Instantly share code, notes, and snippets.

@tfausak
Last active November 18, 2018 21:25
Show Gist options
  • 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 as ByteString
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.Text.Encoding as Encoding
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,096
-- submissions received, 3,735 of them appear to be submitted by a script.
-- This function is responsible for identifying them.
shouldIgnore :: Response -> Bool
shouldIgnore x =
let
isNull = Set.null . multipleToSet
isNotNull = not . isNull
isBadRating r = Maybe.isNothing r || Just 4 <= r || r <= Just 9
isOnly = (==) . Multiple . Set.singleton . Text.pack
in isBadRating (responseQ2 x)
&& is "Yes" (responseQ3 x)
&& Maybe.isNothing (responseQ4 x)
&& isNull (responseQ5 x)
&& Maybe.isJust (responseQ7 x)
&& Maybe.isJust (responseQ8 x)
&& Maybe.isJust (responseQ9 x)
&& isNotNull (responseQ10 x)
&& Maybe.isJust (responseQ11 x)
&& contains "Java" (responseQ14 x)
&& isNull (responseQ16 x)
&& isBadRating (responseQ20 x)
&& Maybe.isNothing (responseQ21 x)
&& Maybe.isNothing (responseQ22 x)
&& isNotNull (responseQ23 x)
&& isOnly "Linux" (responseQ25 x)
&& isBadRating (responseQ27 x)
&& isOnly "GHC" (responseQ28 x)
&& isOnly "Stack" (responseQ30 x)
&& is "Yes" (responseQ32 x)
&& isBadRating (responseQ40 x)
&& isOnly "Stack" (responseQ41 x)
&& contains "Stackage" (responseQ47 x)
&& isBadRating (responseQ53 x)
&& isNull (responseQ54 x)
&& isNull (responseQ56 x)
&& isBadRating (responseQ58 x)
&& isBadRating (responseQ63 x)
&& Maybe.isNothing (responseQ89 x)
&& Maybe.isNothing (responseQ91 x)
&& isBadRating (responseQ94 x)
&& Maybe.isNothing (responseQ95 x)
&& Maybe.isNothing (responseQ96 x)
&& Maybe.isNothing (responseQ97 x)
&& Maybe.isNothing (responseQ98 x)
&& Maybe.isNothing (responseQ99 x)
&& Maybe.isNothing (responseQ100 x)
&& Maybe.isNothing (responseQ101 x)
&& Maybe.isNothing (responseQ102 x)
&& Maybe.isNothing (responseQ103 x)
&& Maybe.isNothing (responseQ104 x)
&& Maybe.isNothing (responseQ105 x)
&& isBadRating (responseQ107 x)
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
LazyByteString.writeFile
(FilePath.combine outputDirectory
$ FilePath.addExtension "responses" "csv"
)
. Csv.encodeDefaultOrderedByName
$ Vector.toList responses
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 libraries", "Haskell lacks critical libraries")
, (Shown, "Missing tooling", "Haskell lacks critical tools")
, ( Hidden
, "Missing platforms"
, "Haskell does not support the platforms I need"
)
, ( Hidden
, "Bad documentation"
, "Haskell's documentation is not good enough"
)
, (Hidden, "Bad performance", "Haskell's performance is not good enough")
, (Hidden, "Missing features", "Haskell lacks critical features")
]
makeMultipleBar
responseQ14
14
"Which programming languages other than Haskell are you fluent in?"
[ (Shown, "Python", "Python")
, (Shown, "JavaScript", "JavaScript")
, (Shown, "Java", "Java")
, (Shown, "C", "C")
, (Shown, "C++", "C++")
, (Shown, "Shell", "Shell")
, (Shown, "C#", "C#")
, (Shown, "Scala", "Scala")
, (Shown, "Ruby", "Ruby")
, (Hidden, "Rust", "Rust")
, (Shown, "TypeScript", "TypeScript")
, (Hidden, "PHP", "PHP")
, (Hidden, "Go", "Go")
, (Hidden, "Clojure", "Clojure")
, (Hidden, "Assembly", "Assembly")
, (Hidden, "Ocaml", "Ocaml")
, (Hidden, "Perl", "Perl")
, (Hidden, "R", "R")
, (Hidden, "Lua", "Lua")
, (Hidden, "F#", "F#")
, (Hidden, "Erlang", "Erlang")
, (Hidden, "Matlab", "Matlab")
, (Hidden, "Objective-C", "Objective-C")
, (Hidden, "Swift", "Swift")
, (Hidden, "Kotlin", "Kotlin")
, (Hidden, "Groovy", "Groovy")
, (Hidden, "VB.NET", "VB.NET")
, (Hidden, "VBA", "VBA")
, (Hidden, "Julia", "Julia")
, (Hidden, "Hack", "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, "Gaming", "Gaming")
, (Shown, "Health", "Healthcare or medical")
, (Shown, "Government", "Government")
, (Shown, "Embedded", "Embedded")
, (Shown, "Mobile", "Mobile")
]
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, "No", "No"), (Shown, "Yes", "Yes")]
makeMultipleBar
responseQ33
33
"How has upgrading your Haskell compiler broken your code in the past year?"
[ (Shown, "Incompatible deps", "Incompatible dependencies")
, ( Shown
, "Expected changes"
, "Expected changes, such as the MonadFail proposal"
)
, (Shown, "New warnings", "New warnings")
, (Shown, "Compiler bugs", "Compiler bugs")
, (Shown, "Unexpected changes", "Unexpected changes")
]
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, "DeriveGeneric", "DeriveGeneric")
, (Shown, "DeriveFunctor", "DeriveFunctor")
, (Shown, "BangPatterns", "BangPatterns")
, (Hidden, "ScopedTypeVariables", "ScopedTypeVariables")
, (Hidden, "GADTs", "GADTs")
, (Hidden, "FlexibleInstances", "FlexibleInstances")
, (Hidden, "FlexibleContexts", "FlexibleContexts")
, (Hidden, "DeriveFoldable", "DeriveFoldable")
, (Hidden, "RankNTypes", "RankNTypes")
, (Hidden, "TupleSections", "TupleSections")
, (Hidden, "MultiParamTypeClasses", "MultiParamTypeClasses")
, (Hidden, "GeneralisedNewtypeDeriving", "GeneralisedNewtypeDeriving")
, (Hidden, "DeriveTraversable", "DeriveTraversable")
, (Hidden, "DataKinds", "DataKinds")
, (Hidden, "TypeApplications", "TypeApplications")
, (Hidden, "TypeOperators", "TypeOperators")
, (Hidden, "KindSignatures", "KindSignatures")
, (Hidden, "TypeFamilies", "TypeFamilies")
, (Hidden, "ApplicativeDo", "ApplicativeDo")
, (Hidden, "StandaloneDeriving", "StandaloneDeriving")
, (Hidden, "ConstraintKinds", "ConstraintKinds")
, (Hidden, "DerivingVia", "DerivingVia")
, (Hidden, "ViewPatterns", "ViewPatterns")
, (Hidden, "InstanceSigs", "InstanceSigs")
, (Hidden, "MultiWayIf", "MultiWayIf")
, (Hidden, "RecordWildCards", "RecordWildCards")
, (Hidden, "FunctionalDependencies", "FunctionalDependencies")
, (Hidden, "DeriveDataTypeable", "DeriveDataTypeable")
, (Hidden, "EmptyCase", "EmptyCase")
, (Hidden, "NamedFieldPuns", "NamedFieldPuns")
, (Hidden, "EmptyDataDecls", "EmptyDataDecls")
, (Hidden, "ExplicitForAll", "ExplicitForAll")
, (Hidden, "DerivingStrategies", "DerivingStrategies")
, (Hidden, "DeriveAnyClass", "DeriveAnyClass")
, (Hidden, "BinaryLiterals", "BinaryLiterals")
, (Hidden, "DefaultSignatures", "DefaultSignatures")
, (Hidden, "NumericUnderscores", "NumericUnderscores")
, (Hidden, "PatternSynonyms", "PatternSynonyms")
, (Hidden, "DuplicateRecordFields", "DuplicateRecordFields")
, (Hidden, "ExistentialQuantification", "ExistentialQuantification")
, (Hidden, "OverloadedLists", "OverloadedLists")
, (Hidden, "PolyKinds", "PolyKinds")
, (Hidden, "GADTSyntax", "GADTSyntax")
, (Hidden, "BlockArguments", "BlockArguments")
, (Hidden, "NoImplicitPrelude", "NoImplicitPrelude")
, (Hidden, "DeriveLift", "DeriveLift")
, (Hidden, "PatternGuards", "PatternGuards")
, (Hidden, "AutoDeriveTypeable", "AutoDeriveTypeable")
, (Hidden, "UnicodeSyntax", "UnicodeSyntax")
, (Hidden, "TypeSynonymInstances", "TypeSynonymInstances")
, (Hidden, "PartialTypeSignatures", "PartialTypeSignatures")
, (Hidden, "NoMonomorphismRestriction", "NoMonomorphismRestriction")
, (Hidden, "TypeInType", "TypeInType")
, (Hidden, "TemplateHaskell", "TemplateHaskell")
, (Hidden, "DisambiguateRecordFields", "DisambiguateRecordFields")
, (Hidden, "TypeFamilyDependencies", "TypeFamilyDependencies")
, (Hidden, "QuasiQuotes", "QuasiQuotes")
, (Hidden, "RecordPuns", "RecordPuns")
, (Hidden, "PackageImports", "PackageImports")
, (Hidden, "QuantifiedConstraints", "QuantifiedConstraints")
, (Hidden, "AllowAmbiguousTypes", "AllowAmbiguousTypes")
, (Hidden, "Arrows", "Arrows")
, (Hidden, "EmptyDataDeriving", "EmptyDataDeriving")
, (Hidden, "NamedWildCards", "NamedWildCards")
, (Hidden, "NegativeLiterals", "NegativeLiterals")
, (Hidden, "ParallelListComp", "ParallelListComp")
, (Hidden, "DoAndIfThenElse", "DoAndIfThenElse")
, (Hidden, "MonadComprehensions", "MonadComprehensions")
, (Hidden, "OverloadedLabels", "OverloadedLabels")
, (Hidden, "RecursiveDo", "RecursiveDo")
, (Hidden, "NumDecimals", "NumDecimals")
, (Hidden, "NullaryTypeClasses", "NullaryTypeClasses")
, (Hidden, "PatternSignatures", "PatternSignatures")
, (Hidden, "Rank2Types", "Rank2Types")
, (Hidden, "ForeignFunctionInterface", "ForeignFunctionInterface")
, (Hidden, "UnboxedTuples", "UnboxedTuples")
, (Hidden, "StarIsType", "StarIsType")
, (Hidden, "RoleAnnotations", "RoleAnnotations")
, (Hidden, "MagicHash", "MagicHash")
, (Hidden, "LiberalTypeSynonyms", "LiberalTypeSynonyms")
, (Hidden, "CPP", "CPP")
, (Hidden, "HexFloatLiterals", "HexFloatLiterals")
, (Hidden, "MonadFailDesugaring", "MonadFailDesugaring")
, (Hidden, "StrictData", "StrictData")
, (Hidden, "ExplicitNamespaces", "ExplicitNamespaces")
, (Hidden, "UnboxedSums", "UnboxedSums")
, (Hidden, "UndecidableInstances", "UndecidableInstances")
, (Hidden, "ImplicitParams", "ImplicitParams")
, (Hidden, "ConstrainedClassMethods", "ConstrainedClassMethods")
, (Hidden, "DoRec", "DoRec")
, (Hidden, "OverlappingInstances", "OverlappingInstances")
, (Hidden, "Strict", "Strict")
, (Hidden, "DatatypeContexts", "DatatypeContexts")
, (Hidden, "CApiFFI", "CApiFFI")
, (Hidden, "TransformListComp", "TransformListComp")
, (Hidden, "TemplateHaskellQuotes", "TemplateHaskellQuotes")
, (Hidden, "PolymorphicComponents", "PolymorphicComponents")
, (Hidden, "RelaxedPolyRec", "RelaxedPolyRec")
, (Hidden, "ExtendedDefaultRules", "ExtendedDefaultRules")
, (Hidden, "PostfixOperators", "PostfixOperators")
, (Hidden, "NPlusKPatterns", "NPlusKPatterns")
, (Hidden, "ParallelArrays", "ParallelArrays")
, (Hidden, "ImpredicativeTypes", "ImpredicativeTypes")
, (Hidden, "InterruptibleFFI", "InterruptibleFFI")
, (Hidden, "AlternativeLayoutRule", "AlternativeLayoutRule")
, (Hidden, "NoTraditionalRecordSyntax", "NoTraditionalRecordSyntax")
, (Hidden, "RebindableSyntax", "RebindableSyntax")
, (Hidden, "UnliftedFFITypes", "UnliftedFFITypes")
, (Hidden, "UndecidableSuperClasses", "UndecidableSuperClasses")
, (Hidden, "RelaxedLayout", "RelaxedLayout")
, ( Hidden
, "AlternativeLayoutRuleTransitional"
, "AlternativeLayoutRuleTransitional"
)
, (Hidden, "MonoLocalBinds", "MonoLocalBinds")
, (Hidden, "JavaScriptFFI", "JavaScriptFFI")
, (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, "IntelliJ IDEA", "IntelliJ IDEA")
, (Shown, "Notepad++", "Notepad++")
]
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, "HUnit", "HUnit")
, (Shown, "Tasty", "Tasty")
, (Shown, "Hedgehog", "Hedgehog")
, (Shown, "SmallCheck", "SmallCheck")
, (Shown, "HTF", "Haskell Test Framework")
, (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, "Stack Overflow", "Stack Overflow")
, (Shown, "Meetups", "Meetups")
, (Shown, "Mailing lists", "Mailing lists")
, (Shown, "Slack", "Slack")
, (Hidden, "Commerical conferences", "Conferences (commercial)")
, (Hidden, "Academic conferences", "Conferences (academic)")
, (Hidden, "Discord", "Discord")
, (Hidden, "Gitter", "Gitter")
, (Hidden, "Lobsters", "Lobsters")
, (Hidden, "Telegram", "Telegram")
, (Hidden, "Mastodon", "Mastodon")
, (Hidden, "Matrix/Riot", "Matrix/Riot")
]
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?"
[ (Shown, "United States", "United States")
, (Shown, "United Kingdom", "United Kingdom")
, (Shown, "Germany", "Germany")
, (Shown, "Australia", "Australia")
, (Shown, "France", "France")
, (Hidden, "Russia", "Russia")
, (Hidden, "Canada", "Canada")
, (Hidden, "Sweden", "Sweden")
, (Hidden, "Netherlands", "Netherlands")
, (Hidden, "India", "India")
, (Hidden, "Japan", "Japan")
, (Hidden, "Italy", "Italy")
, (Hidden, "Poland", "Poland")
, (Hidden, "Finland", "Finland")
, (Hidden, "Switzerland", "Switzerland")
, (Hidden, "Austria", "Austria")
, (Hidden, "Norway", "Norway")
, (Hidden, "Czechia", "Czechia")
, (Hidden, "Denmark", "Denmark")
, (Hidden, "Belgium", "Belgium")
, (Hidden, "Spain", "Spain")
, (Hidden, "New Zealand", "New Zealand")
, (Hidden, "Brazil", "Brazil")
, (Hidden, "China", "China")
, (Hidden, "Ireland", "Ireland")
, (Hidden, "Israel", "Israel")
, (Hidden, "Ukraine", "Ukraine")
, (Hidden, "Portugal", "Portugal")
, (Hidden, "Croatia", "Croatia")
, (Hidden, "Belarus", "Belarus")
, (Hidden, "Romania", "Romania")
, (Hidden, "Argentina", "Argentina")
, (Hidden, "Bulgaria", "Bulgaria")
, (Hidden, "Greece", "Greece")
, (Hidden, "Indonesia", "Indonesia")
, (Hidden, "Latvia", "Latvia")
, (Hidden, "South Africa", "South Africa")
, (Hidden, "Turkey", "Turkey")
, (Hidden, "Ecuador", "Ecuador")
, (Hidden, "Estonia", "Estonia")
, (Hidden, "Hungary", "Hungary")
, (Hidden, "Kenya", "Kenya")
, (Hidden, "Singapore", "Singapore")
, (Hidden, "Mexico", "Mexico")
, (Hidden, "Thailand", "Thailand")
, (Hidden, "Algeria", "Algeria")
, (Hidden, "Armenia", "Armenia")
, (Hidden, "Azerbaijan", "Azerbaijan")
, (Hidden, "Bolivia", "Bolivia")
, (Hidden, "Cameroon", "Cameroon")
, (Hidden, "Chile", "Chile")
, (Hidden, "Colombia", "Colombia")
, (Hidden, "Egypt", "Egypt")
, (Hidden, "Guatemala", "Guatemala")
, (Hidden, "Iceland", "Iceland")
, (Hidden, "Iran", "Iran")
, (Hidden, "Kazakhstan", "Kazakhstan")
, (Hidden, "Lebanon", "Lebanon")
, (Hidden, "Malta", "Malta")
, (Hidden, "Nepal", "Nepal")
, (Hidden, "Nigeria", "Nigeria")
, (Hidden, "Pakistan", "Pakistan")
, (Hidden, "Paraguay", "Paraguay")
, (Hidden, "Peru", "Peru")
, (Hidden, "Philippines", "Philippines")
, (Hidden, "Serbia", "Serbia")
, (Hidden, "Slovakia", "Slovakia")
, (Hidden, "Slovenia", "Slovenia")
, (Hidden, "South Korea", "South Korea")
, (Hidden, "Syria", "Syria")
, (Hidden, "Uganda", "Uganda")
, (Hidden, "Vietnam", "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, "I don't remember", "I don't remember")
]
makeSingleBar
responseQ109
109
"How did you hear about this survey?"
[ (Shown, "Reddit", "Reddit")
, (Shown, "Twitter", "Twitter")
, (Shown, "Mailing list", "Mailing list")
, (Shown, "Haskell Weekly", "Haskell Weekly")
, (Shown, "Lobsters", "Lobsters")
, (Shown, "Slack", "Slack")
, (Hidden, "Discord", "Discord")
, (Shown, "Other", "Other")
, (Shown, "In person", "In person")
, (Hidden, "IRC", "IRC")
, (Hidden, "Telegram", "Telegram")
, (Hidden, "Gitter", "Gitter")
, (Hidden, "Matrix/Riot", "Matrix/Riot")
, (Hidden, "Mastodon", "Mastodon")
]
IO.hPutStrLn handle "</body>"
IO.hPutStrLn handle "</html>"
IO.hFlush handle
data Response = Response
{ responseQ0 :: Int
, responseQ1 :: Date
, responseQ2 :: Maybe Int
, responseQ3 :: Maybe Text.Text
, responseQ4 :: Maybe Text.Text
, responseQ5 :: Multiple Text.Text
, responseQ6 :: Maybe Text.Text
, responseQ7 :: Maybe Text.Text
, responseQ8 :: Maybe Text.Text
, responseQ9 :: Maybe Text.Text
, responseQ10 :: Multiple Text.Text
, responseQ11 :: Maybe Text.Text
, responseQ12 :: Multiple Text.Text
, responseQ13 :: Maybe Text.Text
, responseQ14 :: Multiple Text.Text
, responseQ15 :: Maybe Text.Text
, responseQ16 :: Multiple Text.Text
, responseQ17 :: Maybe Text.Text
, responseQ18 :: Multiple Text.Text
, responseQ19 :: Maybe Text.Text
, responseQ20 :: Maybe Int
, responseQ21 :: Maybe Text.Text
, responseQ22 :: Maybe Text.Text
, responseQ23 :: Multiple Text.Text
, responseQ24 :: Maybe Text.Text
, responseQ25 :: Multiple Text.Text
, responseQ26 :: Maybe Text.Text
, responseQ27 :: Maybe Int
, responseQ28 :: Multiple Text.Text
, responseQ29 :: Maybe Text.Text
, responseQ30 :: Multiple Text.Text
, responseQ31 :: Maybe Text.Text
, responseQ32 :: Maybe Text.Text
, responseQ33 :: Multiple Text.Text
, responseQ34 :: Maybe Text.Text
, responseQ35 :: Multiple Text.Text
, responseQ36 :: Maybe Text.Text
, responseQ37 :: Maybe Text.Text
, responseQ38 :: Multiple Text.Text
, responseQ39 :: Maybe Text.Text
, responseQ40 :: Maybe Int
, responseQ41 :: Multiple Text.Text
, responseQ42 :: Maybe Text.Text
, responseQ43 :: Multiple Text.Text
, responseQ44 :: Maybe Text.Text
, responseQ45 :: Multiple Text.Text
, responseQ46 :: Maybe Text.Text
, responseQ47 :: Multiple Text.Text
, responseQ48 :: Maybe Text.Text
, responseQ49 :: Multiple Text.Text
, responseQ50 :: Maybe Text.Text
, responseQ51 :: Multiple Text.Text
, responseQ52 :: Maybe Text.Text
, responseQ53 :: Maybe Int
, responseQ54 :: Multiple Text.Text
, responseQ55 :: Maybe Text.Text
, responseQ56 :: Multiple Text.Text
, responseQ57 :: Maybe Text.Text
, responseQ58 :: Maybe Int
, responseQ59 :: Multiple Text.Text
, responseQ60 :: Maybe Text.Text
, responseQ61 :: Multiple Text.Text
, responseQ62 :: Maybe Text.Text
, responseQ63 :: Maybe Int
, responseQ64 :: Maybe Text.Text
, responseQ65 :: Maybe Text.Text
, responseQ66 :: Maybe Text.Text
, responseQ67 :: Maybe Text.Text
, responseQ68 :: Maybe Text.Text
, responseQ69 :: Maybe Text.Text
, responseQ70 :: Maybe Text.Text
, responseQ71 :: Maybe Text.Text
, responseQ72 :: Maybe Text.Text
, responseQ73 :: Maybe Text.Text
, responseQ74 :: Maybe Text.Text
, responseQ75 :: Maybe Text.Text
, responseQ76 :: Maybe Text.Text
, responseQ77 :: Maybe Text.Text
, responseQ78 :: Maybe Text.Text
, responseQ79 :: Maybe Text.Text
, responseQ80 :: Maybe Text.Text
, responseQ81 :: Maybe Text.Text
, responseQ82 :: Maybe Text.Text
, responseQ83 :: Maybe Text.Text
, responseQ84 :: Maybe Text.Text
, responseQ85 :: Maybe Text.Text
, responseQ86 :: Maybe Text.Text
, responseQ87 :: Maybe Text.Text
, responseQ88 :: Maybe Text.Text
, responseQ89 :: Maybe Text.Text
, responseQ90 :: Maybe Text.Text
, responseQ91 :: Maybe Text.Text
, responseQ92 :: Maybe Text.Text
, responseQ93 :: Maybe Text.Text
, responseQ94 :: Maybe Int
, responseQ95 :: Maybe Text.Text
, responseQ96 :: Maybe Text.Text
, responseQ97 :: Maybe Text.Text
, responseQ98 :: Maybe Text.Text
, responseQ99 :: Maybe Text.Text
, responseQ100 :: Maybe Text.Text
, responseQ101 :: Maybe Text.Text
, responseQ102 :: Maybe Text.Text
, responseQ103 :: Maybe Text.Text
, responseQ104 :: Maybe Text.Text
, responseQ105 :: Maybe Text.Text
, responseQ106 :: Maybe Text.Text
, responseQ107 :: Maybe Int
, responseQ108 :: Maybe Text.Text
, responseQ109 :: Maybe Text.Text
, responseQ110 :: Maybe Text.Text
} deriving (Eq, Show)
instance Csv.DefaultOrdered Response where
headerOrder = const . Csv.header $ fmap snd responseFields
instance Csv.FromRecord Response where
parseRecord record = Response
<$> Csv.index record 0
<*> Csv.index record 1
<*> Csv.index record 2
<*> Csv.index record 3
<*> Csv.index record 4
<*> Csv.index record 5
<*> Csv.index record 6
<*> 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 13
<*> Csv.index record 14
<*> Csv.index record 15
<*> Csv.index record 16
<*> Csv.index record 17
<*> Csv.index record 18
<*> Csv.index record 19
<*> Csv.index record 20
<*> Csv.index record 21
<*> Csv.index record 22
<*> Csv.index record 23
<*> Csv.index record 24
<*> Csv.index record 25
<*> Csv.index record 26
<*> Csv.index record 27
<*> Csv.index record 28
<*> Csv.index record 29
<*> Csv.index record 30
<*> Csv.index record 31
<*> Csv.index record 32
<*> Csv.index record 33
<*> Csv.index record 34
<*> Csv.index record 35
<*> Csv.index record 36
<*> Csv.index record 37
<*> Csv.index record 38
<*> Csv.index record 39
<*> Csv.index record 40
<*> Csv.index record 41
<*> Csv.index record 42
<*> Csv.index record 43
<*> Csv.index record 44
<*> Csv.index record 45
<*> Csv.index record 46
<*> Csv.index record 47
<*> Csv.index record 48
<*> Csv.index record 49
<*> Csv.index record 50
<*> Csv.index record 51
<*> Csv.index record 52
<*> Csv.index record 53
<*> Csv.index record 54
<*> Csv.index record 55
<*> Csv.index record 56
<*> Csv.index record 57
<*> Csv.index record 58
<*> Csv.index record 59
<*> Csv.index record 60
<*> Csv.index record 61
<*> Csv.index record 62
<*> Csv.index record 63
<*> Csv.index record 64
<*> Csv.index record 65
<*> Csv.index record 66
<*> Csv.index record 67
<*> Csv.index record 68
<*> Csv.index record 69
<*> Csv.index record 70
<*> Csv.index record 71
<*> Csv.index record 72
<*> 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 92
<*> Csv.index record 93
<*> 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
instance Csv.ToNamedRecord Response where
toNamedRecord response =
Csv.namedRecord $ fmap (\(f, x) -> (x, f response)) responseFields
responseFields :: [(Response -> Csv.Field, Csv.Name)]
responseFields = fmap
(\(f, x) -> (f, toUtf8 x))
[ (Csv.toField . responseQ0, "Number")
, (Csv.toField . responseQ1, "Submission date")
, (Csv.toField . responseQ2, "HASKELL USAGE")
, (Csv.toField . responseQ3, "Do you use Haskell?")
, ( Csv.toField . responseQ4
, "If you stopped using Haskell, how long did you use it before you stopped?"
)
, (Csv.toField . responseQ5, "If you do not use Haskell, why not?")
, ( Csv.toField . responseQ6
, "Are there any other reasons why you do not use Haskell?"
)
, (Csv.toField . responseQ7, "How long have you been using Haskell?")
, (Csv.toField . responseQ8, "How frequently do you use Haskell?")
, ( Csv.toField . responseQ9
, "How would you rate your proficiency in Haskell?"
)
, (Csv.toField . responseQ10, "Where do you use Haskell?")
, (Csv.toField . responseQ11, "Do you use Haskell at work?")
, (Csv.toField . responseQ12, "If you do not use Haskell at work, why not?")
, ( Csv.toField . responseQ13
, "Are there other reasons why you do not use Haskell at work?"
)
, ( Csv.toField . responseQ14
, "Which programming languages other than Haskell are you fluent in?"
)
, ( Csv.toField . responseQ15
, "What other programming languages are you fluent in?"
)
, ( Csv.toField . responseQ16
, "Which types of software do you develop with Haskell?"
)
, ( Csv.toField . responseQ17
, "What other types of software do you develop with Haskell?"
)
, (Csv.toField . responseQ18, "Which industries do you use Haskell in?")
, (Csv.toField . responseQ19, "What other industries do you use Haskell in?")
, (Csv.toField . responseQ20, "PROJECTS")
, ( Csv.toField . responseQ21
, "How many Haskell projects do you contribute to?"
)
, ( Csv.toField . responseQ22
, "What is the total size of all the Haskell projects you contribute to?"
)
, (Csv.toField . responseQ23, "Which platforms do you develop Haskell on?")
, ( Csv.toField . responseQ24
, "What other platforms do you develop Haskell on?"
)
, (Csv.toField . responseQ25, "Which platforms do you target?")
, (Csv.toField . responseQ26, "What other platforms do you target?")
, (Csv.toField . responseQ27, "COMPILERS")
, (Csv.toField . responseQ28, "Which Haskell compilers do you use?")
, (Csv.toField . responseQ29, "What other Haskell compilers do you use?")
, ( Csv.toField . responseQ30
, "Which installation methods do you use for your Haskell compiler?"
)
, ( Csv.toField . responseQ31
, "What other installation methods do you use for your Haskell compiler?"
)
, ( Csv.toField . responseQ32
, "Has upgrading your Haskell compiler broken your code in the last year?"
)
, ( Csv.toField . responseQ33
, "How has upgrading your Haskell compiler broken your code in the past year?"
)
, ( Csv.toField . responseQ34
, "How else has upgrading your Haskell compiler broken your code in the past year?"
)
, (Csv.toField . responseQ35, "Which versions of GHC do you use?")
, ( Csv.toField . responseQ36
, "How do you feel about the new GHC release schedule?"
)
, ( Csv.toField . responseQ37
, "Why do you feel the way that you do about the new GHC release schedule?"
)
, ( Csv.toField . responseQ38
, "Which GHC language extensions would you like to be enabled by default?"
)
, ( Csv.toField . responseQ39
, "How important do you feel it would be to have a new version of the Haskell standard?"
)
, (Csv.toField . responseQ40, "TOOLING")
, (Csv.toField . responseQ41, "Which build tools do you use for Haskell?")
, ( Csv.toField . responseQ42
, "What other build tools do you use for Haskell?"
)
, (Csv.toField . responseQ43, "Which editors do you use for Haskell?")
, (Csv.toField . responseQ44, "What other editors do you use for Haskell?")
, ( Csv.toField . responseQ45
, "Which version control systems do you use for Haskell?"
)
, ( Csv.toField . responseQ46
, "Which other version control systems do you use for Haskell?"
)
, (Csv.toField . responseQ47, "Where do you get Haskell packages from?")
, (Csv.toField . responseQ48, "Where else do you get Haskell packages from?")
, ( Csv.toField . responseQ49
, "Which libraries do you use to test Haskell code?"
)
, ( Csv.toField . responseQ50
, "What other tools do you use to test Haskell code?"
)
, ( Csv.toField . responseQ51
, "Which libraries do you use to benchmark Haskell code?"
)
, ( Csv.toField . responseQ52
, "What other tools do you use to benchmark Haskell code?"
)
, (Csv.toField . responseQ53, "INFRASTRUCTURE")
, ( Csv.toField . responseQ54
, "Which tools do you use to deploy Haskell applications?"
)
, ( Csv.toField . responseQ55
, "What other tools do you use to deploy Haskell applications?"
)
, (Csv.toField . responseQ56, "Where do you deploy Haskell applications?")
, ( Csv.toField . responseQ57
, "Where else do you deploy Haskell applications?"
)
, (Csv.toField . responseQ58, "COMMUNITY")
, ( Csv.toField . responseQ59
, "Where do you interact with the Haskell community?"
)
, ( Csv.toField . responseQ60
, "Where else do you interact with the Haskell community?"
)
, ( Csv.toField . responseQ61
, "Which of the following Haskell topics would you like to see more written about?"
)
, ( Csv.toField . responseQ62
, "What other Haskell topics would you like to see more written about?"
)
, (Csv.toField . responseQ63, "FEELINGS")
, (Csv.toField . responseQ64, "I feel welcome in the Haskell community.")
, (Csv.toField . responseQ65, "I am satisfied with Haskell as a language.")
, ( Csv.toField . responseQ66
, "What would you change about Haskell the language?"
)
, ( Csv.toField . responseQ67
, "I am satisfied with Haskell's compilers, such as GHC."
)
, ( Csv.toField . responseQ68
, "What would you change about Haskell's compilers?"
)
, ( Csv.toField . responseQ69
, "I am satisfied with Haskell's build tools, such as Cabal."
)
, ( Csv.toField . responseQ70
, "What would you change about Haskell's build tools?"
)
, ( Csv.toField . responseQ71
, "I am satisfied with Haskell's package repositories, such as Hackage."
)
, ( Csv.toField . responseQ72
, "What would you change about Haskell's package repositories?"
)
, ( Csv.toField . responseQ73
, "I can find Haskell libraries for the things that I need."
)
, (Csv.toField . responseQ74, "I think Haskell libraries are high quality.")
, ( Csv.toField . responseQ75
, "I have a good understanding of Haskell best practices."
)
, ( Csv.toField . responseQ76
, "I think Haskell libraries are well documented."
)
, ( Csv.toField . responseQ77
, "I can easily compare competing Haskell libraries to select the best one."
)
, ( Csv.toField . responseQ78
, "I think that Haskell libraries are easy to use."
)
, ( Csv.toField . responseQ79
, "I think that Haskell libraries provide a stable API."
)
, ( Csv.toField . responseQ80
, "I think that Haskell libraries work well together."
)
, ( Csv.toField . responseQ81
, "I think that software written in Haskell is easy to maintain."
)
, ( Csv.toField . responseQ82
, "Once my Haskell program compiles, it generally does what I intended."
)
, (Csv.toField . responseQ83, "I think that Haskell libraries perform well.")
, (Csv.toField . responseQ84, "Haskell's performance meets my needs.")
, ( Csv.toField . responseQ85
, "I can easily reason about the performance of my Haskell code."
)
, (Csv.toField . responseQ86, "I would recommend using Haskell to others.")
, ( Csv.toField . responseQ87
, "I would prefer to use Haskell for my next new project."
)
, (Csv.toField . responseQ88, "Haskell is working well for my team.")
, (Csv.toField . responseQ89, "Haskell is critical to my company's success.")
, ( Csv.toField . responseQ90
, "As a candidate, I can easily find Haskell jobs."
)
, ( Csv.toField . responseQ91
, "As a hiring manager, I can easily find qualified Haskell candidates."
)
, (Csv.toField . responseQ92, "What is your favorite thing about Haskell?")
, ( Csv.toField . responseQ93
, "What is your least favorite thing about Haskell?"
)
, (Csv.toField . responseQ94, "DEMOGRAPHICS")
, (Csv.toField . responseQ95, "Which country do you live in?")
, (Csv.toField . responseQ96, "How old are you?")
, (Csv.toField . responseQ97, "What is your gender?")
, (Csv.toField . responseQ98, "Do you identify as transgender?")
, (Csv.toField . responseQ99, "Are you a student?")
, ( Csv.toField . responseQ100
, "What is the highest level of education you have completed?"
)
, (Csv.toField . responseQ101, "What is your employment status?")
, (Csv.toField . responseQ102, "How large is the company you work for?")
, (Csv.toField . responseQ103, "How many years have you been coding?")
, ( Csv.toField . responseQ104
, "How many years have you been coding professionally?"
)
, (Csv.toField . responseQ105, "Do you code as a hobby?")
, ( Csv.toField . responseQ106
, "Have you contributed to any open source projects?"
)
, (Csv.toField . responseQ107, "META SURVEY")
, (Csv.toField . responseQ108, "Did you take last year's survey?")
, (Csv.toField . responseQ109, "How did you hear about this survey?")
, ( Csv.toField . responseQ110
, "Do you have any feedback about the survey itself?"
)
]
newtype Date
= Date Time.Day
deriving (Eq, Show)
instance Csv.FromField Date where
parseField field = do
string <- Csv.parseField field
Date <$> Time.parseTimeM False Time.defaultTimeLocale "%Y-%m-%d" string
instance Csv.ToField Date where
toField = Csv.toField . Time.formatTime Time.defaultTimeLocale "%Y-%m-%d" . dateToDay
dateToDay :: Date -> Time.Day
dateToDay (Date day) = day
newtype Multiple a
= Multiple (Set.Set a)
deriving (Eq, Show)
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
instance Csv.ToField a => Csv.ToField (Multiple a) where
toField = Csv.toField . Csv.encode . pure . Set.toAscList . multipleToSet
multipleToSet :: Multiple a -> Set.Set a
multipleToSet (Multiple set) = set
data Visibility
= Hidden
| Shown
deriving (Eq, Show)
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 "\n<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"
toUtf8 :: String -> ByteString.ByteString
toUtf8 = Encoding.encodeUtf8 . Text.pack
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment