/
Solution.hs
146 lines (99 loc) · 4.21 KB
/
Solution.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
{-# LANGUAGE OverloadedStrings #-}
module Y2017.M05.D24.Solution where
import Data.Aeson -- available via cabal
import Data.Aeson.Types (Parser)
import Data.Text (Text)
-- below imports available via 1HaskellADay git repository
import Wikidata.Query.Aeson
import Wikidata.Query.Endpoint
{--
So, how far in depth do you go before you're 'done.'
There is a scientific approach to this if one has a tree or DAG with only
one root. Do we have this here?
Languages have roots, but language families have roots, too, and the families
of languages are in no way flat nor well-balanced.
Post this query to the wikidata endpoint and examine your results:
--}
languageRootsQuery :: String
languageRootsQuery =
unlines ["SELECT ?language ?languageLabel ?root ?rootLabel",
"?parent ?parentLabel ?grand ?grandLabel ?great ?greatLabel ",
"?great2 ?great2Label ?nspeakers WHERE {",
"?language wdt:P31 wd:Q34770 .",
"?language wdt:P279 ?root.",
"OPTIONAL { ?root wdt:P279 ?parent.",
"?parent wdt:P279 ?grand.",
"?grand wdt:P279 ?great.",
"?great wdt:P279 ?great2 }.",
"?language wdt:P1098 ?nspeakers.",
"SERVICE wikibase:label {",
"bd:serviceParam wikibase:language \"en\" .",
"}",
"} ORDER BY ?nspeakers"]
-- The structure of this query is as follows:
data Language = Lang { lang, root :: String, nspeakers :: Integer,
parent, grand, great, great2 :: Maybe String }
deriving (Eq, Show)
{--
-- first of all we need to parse JSON to a Maybe-value. Aeson has this, but
-- doesn't have a convenient way to parse Maybe-ness in depth.
parseOpt :: FromJSON a => Value -> Text -> Parser (Maybe a)
parseOpt (Object o) key = o .:? key >>= maybe (return Nothing) (.: "value")
--}
-- now we need an intermediary for numeric encoding
data LangString = L { l', r', n' :: String, p1,g1,g2,g3 :: Maybe String }
instance FromJSON LangString where
parseJSON o = L <$> parseVal o "languageLabel" <*> parseVal o "rootLabel"
<*> parseVal o "nspeakers" <*> parseOpt o "parentLabel"
<*> parseOpt o "grandLabel" <*> parseOpt o "greatLabel"
<*> parseOpt o "great2Label"
-- with that, we simply convert from LangString to Language
toLang :: LangString -> Language
toLang (L a b c d e f g) = Lang a b (read c) d e f g
-- and we formulate our query thusly:
queryLangRoots :: IO [Language]
queryLangRoots = map toLang . reifyWikiResults <$> sparql languageRootsQuery
{--
>>> head <$> queryLangRoots
Lang {lang = "Mattole language", root = "indigenous languages of the Americas",
nspeakers = 0, parent = Just "human language", grand = Just "language",
great = Just "languoid", great2 = Just "abstract object"}
>>> length <$> queryLangRoots
1036
I love that Haskell just works the first run because the compiler catches your
errors before they get into the runtime.
--}
-- We'll move the rest of this fun-part here to tomorrow's problem, as
-- parseOpt was a moral victory for me today. Rolling parseOpt into
-- Wikidata.Query.Aeson
{-- Moving below to tomorrow's problem:
-- Now, here comes the fun part.
-- 0. Construct a graph of languages from the results returned.
type Root = String
data LanguageGraph = WhatDoesYourLanguageGraphLookLike
-- hint: maybe look at the Regressive Imagery Dictionary graph?
languageGraph :: [Language] -> LanguageGraph
languageGraph langs = undefined
-- 1. What is/are the root node(s)?
roots :: [Language] -> [Root]
roots langs = undefined
-- 2. Which languages are in the greatest depth?
type Depth = Int
deepest :: [Language] -> (Depth, [String])
deepest langs = undefined
-- 3. Enumerate the roots from start to that 'deepest' language
pathTo :: [Language] -> String -> [String]
pathTo langs lang = undefined
-- 4. which roots have the greatest breath?
type Breath = Int
bigBreath :: {- eheh -} [Language] -> (Breath, [Root])
bigBreath langs = undefined
-- 5. Which roots have the most descendents?
type Count = Int
bigFamily :: [Language] -> (Count, [Root])
bigFamily langs = undefined
-- 6. Which roots have the most speakers of the various languages?
mostSpeakers :: [Language] -> (Count, [Root])
mostSpeakers langs = undefined
-- Tomorrow we'll look at a language-tree visualization.
--}