From afa9d701538b9e56622a0bfdf8e04aa358c9cd82 Mon Sep 17 00:00:00 2001 From: Ben Sima Date: Wed, 15 Apr 2020 10:06:24 -0700 Subject: Reformatting Now I'm using ormolu instead of brittany for Haskell formatting now. Figured I should just make all of these big changes at once. --- Biz/Ibb/Client.hs | 38 +- Biz/Ibb/Core.hs | 184 +++++---- Biz/Ibb/Influencers.hs | 908 ++++++++++++++++++++++++------------------ Biz/Ibb/Keep.hs | 116 +++--- Biz/Ibb/Look.hs | 22 +- Biz/Ibb/Move.hs | 62 +-- Biz/Ibb/Server.hs | 136 +++---- Biz/Language/Bs.hs | 5 +- Biz/Language/Bs/Cli.hs | 46 ++- Biz/Language/Bs/Eval.hs | 183 ++++----- Biz/Language/Bs/Expr.hs | 157 ++++---- Biz/Language/Bs/Parser.hs | 84 ++-- Biz/Language/Bs/Primitives.hs | 179 +++++---- Biz/Language/Bs/Repl.hs | 11 +- 14 files changed, 1135 insertions(+), 996 deletions(-) (limited to 'Biz') diff --git a/Biz/Ibb/Client.hs b/Biz/Ibb/Client.hs index e40ff36..89e0ffc 100644 --- a/Biz/Ibb/Client.hs +++ b/Biz/Ibb/Client.hs @@ -16,23 +16,25 @@ -- : dep ghcjs-base module Biz.Ibb.Client where -import Alpha -import Biz.Ibb.Core ( Action(..) - , see - , init - ) -import Biz.Ibb.Move ( move ) -import Miso ( App(..) - , defaultEvents - , miso - ) +import Alpha +import Biz.Ibb.Core + ( Action (..), + init, + see, + ) +import Biz.Ibb.Move (move) +import Miso + ( App (..), + defaultEvents, + miso, + ) main :: IO () -main = miso $ \u -> App { model = init u, .. } - where - initialAction = FetchPeople - update = move - view = see - events = defaultEvents - subs = [] - mountPoint = Nothing +main = miso $ \u -> App {model = init u, ..} + where + initialAction = FetchPeople + update = move + view = see + events = defaultEvents + subs = [] + mountPoint = Nothing diff --git a/Biz/Ibb/Core.hs b/Biz/Ibb/Core.hs index fb82ff0..2c1fbae 100644 --- a/Biz/Ibb/Core.hs +++ b/Biz/Ibb/Core.hs @@ -1,53 +1,59 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE NoImplicitPrelude #-} -- | Main app logic module Biz.Ibb.Core where -import Alpha -import Network.RemoteData -import Data.Aeson hiding ( Success ) -import Data.Data ( Data - , Typeable - ) -import Data.Text ( Text ) -import GHC.Generics ( Generic ) -import Miso -import Miso.String -import Servant.API -import Servant.Links +import Alpha +import Data.Aeson hiding (Success) +import Data.Data + ( Data, + Typeable, + ) +import Data.Text (Text) +import GHC.Generics (Generic) +import Miso +import Miso.String +import Network.RemoteData +import Servant.API +import Servant.Links -- * entity data types -data Person = Person - { _name :: Text - -- ^ Their full name. - , _pic :: Text - -- ^ A link to their picture. - , _twitter :: Text - -- ^ Their twitter handle, without the `@` prefix. - , _website :: Text - -- ^ Their main website, fully formed: `https://example.com` - , _books :: [Book] - -- ^ A short list of the books they recommend. - , _blurb :: Text - -- ^ A short "about" section, like you would see on the jacket flap of a book. - } deriving (Generic, Show, Eq, Typeable, Data, Ord) +data Person + = Person + { -- | Their full name. + _name :: Text, + -- | A link to their picture. + _pic :: Text, + -- | Their twitter handle, without the `@` prefix. + _twitter :: Text, + -- | Their main website, fully formed: `https://example.com` + _website :: Text, + -- | A short list of the books they recommend. + _books :: [Book], + -- | A short "about" section, like you would see on the jacket flap of a book. + _blurb :: Text + } + deriving (Generic, Show, Eq, Typeable, Data, Ord) instance FromJSON Person + instance ToJSON Person -data Book = Book - { _title :: Text - , _author :: Text - , _amznref :: Text - -- ^ Amazon REF number, for creating affiliate links. - } deriving (Generic, Show, Eq, Typeable, Data, Ord) +data Book + = Book + { _title :: Text, + _author :: Text, + -- | Amazon REF number, for creating affiliate links. + _amznref :: Text + } + deriving (Generic, Show, Eq, Typeable, Data, Ord) instance FromJSON Book + instance ToJSON Book -- * app data types @@ -56,10 +62,12 @@ type AppRoutes = Home type Home = View Action -data Model = Model - { uri :: URI - , people :: WebData [Person] - } deriving (Show, Eq) +data Model + = Model + { uri :: URI, + people :: WebData [Person] + } + deriving (Show, Eq) type WebData a = RemoteData MisoString a @@ -87,57 +95,63 @@ goHome :: URI goHome = linkURI $ safeLink (Proxy :: Proxy AppRoutes) (Proxy :: Proxy Home) see :: Model -> View Action -see m = div_ - [class_ "container mt-5"] - [ div_ - [class_ "jumbotron"] - [ h1_ [class_ "display-4"] [text "Influenced by books"] - , p_ [class_ "lead"] - [text "Influential people and the books that made them."] - , p_ - [class_ "lead"] - [ a_ - [href_ "http://eepurl.com/ghBFjv"] - [ text - "Get new book recommendations from the world's influencers in your email." - ] - ] +see m = + div_ + [class_ "container mt-5"] + [ div_ + [class_ "jumbotron"] + [ h1_ [class_ "display-4"] [text "Influenced by books"], + p_ + [class_ "lead"] + [text "Influential people and the books that made them."], + p_ + [class_ "lead"] + [ a_ + [href_ "http://eepurl.com/ghBFjv"] + [ text + "Get new book recommendations from the world's influencers in your email." + ] + ] + ], + div_ [class_ "card-columns"] $ case people m of + NotAsked -> [text "Initializing..."] + Loading -> [text "Loading..."] + Failure err -> [text err] + Success ps -> seePerson [text "Initializing..."] - Loading -> [text "Loading..."] - Failure err -> [text err] - Success ps -> seePerson View Action -seePerson person = div_ - [class_ "card"] - [ div_ [class_ "card-img"] - [img_ [class_ "card-img img-fluid", src_ $ ms $ _pic person]] - , div_ - [class_ "card-body"] - [ h4_ [class_ "card-title"] [text $ ms $ _name person] - , h6_ - [] - [ a_ - [ class_ "fab fa-twitter" - , href_ $ "https://twitter.com/" <> (ms $ _twitter person) +seePerson person = + div_ + [class_ "card"] + [ div_ + [class_ "card-img"] + [img_ [class_ "card-img img-fluid", src_ $ ms $ _pic person]], + div_ + [class_ "card-body"] + [ h4_ [class_ "card-title"] [text $ ms $ _name person], + h6_ + [] + [ a_ + [ class_ "fab fa-twitter", + href_ $ "https://twitter.com/" <> (ms $ _twitter person) + ] + [], + a_ [class_ "fas fa-globe", href_ $ ms $ _website person] [] + ], + p_ + [class_ "card-text"] + [text $ ms $ _blurb person, ul_ [] $ seeBook View Action -seeBook book = li_ - [] - [ a_ - [ class_ "text-dark" - , href_ $ "https://www.amazon.com/dp/" <> (ms $ _amznref book) - ] - [text $ ms $ _title book] - ] +seeBook book = + li_ + [] + [ a_ + [ class_ "text-dark", + href_ $ "https://www.amazon.com/dp/" <> (ms $ _amznref book) + ] + [text $ ms $ _title book] + ] diff --git a/Biz/Ibb/Influencers.hs b/Biz/Ibb/Influencers.hs index c31e962..cf53cc0 100644 --- a/Biz/Ibb/Influencers.hs +++ b/Biz/Ibb/Influencers.hs @@ -1,6 +1,6 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE OverloadedStrings #-} module Biz.Ibb.Influencers where @@ -8,400 +8,512 @@ import Biz.Ibb.Core allPeople :: [Person] allPeople = - [ Person { _name = "Joe Rogan" - , _pic = "https://pbs.twimg.com/profile_images/552307347851210752/vrXDcTFC_400x400.jpeg" - , _twitter = "joerogan" - , _blurb = "Stand up comic/mixed martial arts fanatic/psychedelic adventurer Host of The Joe Rogan Experience" - , _website = "http://joerogan.com" - , _books = [ Book {_title = "Food of the Gods" - , _author = "Terence McKenna" - , _amznref = "0553371304" - } - , Book { _title = "The War of Art" - , _author ="Steven Pressfield" - , _amznref ="B007A4SDCG" - } - ] - } - , Person { _name = "Beyoncé" - , _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTxT84sF19lxdnSiblIXAp-Y4wAigpQn8sZ2GtAerIR_ApiiEJfFQ" - , _twitter = "Beyonce" - , _blurb = "American singer, songwriter, actress, record producer and dancer" - , _website = "http://beyonce.com" - , _books = [ Book { _title = "What Will It Take To Make A Woman President?" - , _author = "Marianne Schnall" - , _amznref = "B00E257Y7G"} - ] - } - , Person { _name = "Barrack Obama" - , _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQeLzftR36p0hYI-EKNa5fm7CYDuN-vyz23_R48ocqa8X1nPr6C" - , _twitter = "BarackObama" - , _blurb = "Dad, husband, President, citizen. 44th POTUS" - , _website = "http://barackobama.com" - , _books = [ Book { _title = "An American Marriage" - , _author = "Tayari Jones" - , _amznref = "B01NCUXEFR"} - , Book { _title = "Americanah" - , _author = "Chimamanda Ngozi Adichie" - , _amznref = "B00A9ET4MC"} - ] - } - , Person { _name = "Warren Buffet" - , _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQQbmnUykS6zqgzaf44tsq1RAsnHe6H7fapEoSqUwAoJGSFKbAPSw" - , _twitter = "WarrenBuffett" - , _blurb = "Chairman and CEO of Berkshire Hathaway" - , _website = "http://berkshirehathaway.com" - , _books = [ Book { _title = "The Intelligent Investor" - , _author = "Benjamin Graham" - , _amznref = "B000FC12C8"} - , Book { _title = "Security Analysis" - , _author = "Benjamin Graham" - , _amznref = "B0037JO5J8"} - ] - } - , Person { _name = "Bill Gates" - , _pic = "https://pbs.twimg.com/profile_images/988775660163252226/XpgonN0X_400x400.jpg" - , _twitter = "BillGates" - , _blurb = "Sharing things I'm learning through my foundation work and other interests. Founder of Microsoft and Bill & Melinda Gates Foundation" - , _website = "https://www.gatesnotes.com" - , _books = [ Book { _title = "Leonardo da Vinci" - , _author = "Walter Isaacson" - , _amznref = "1501139169" - } - , Book { _title = "Educated" - , _author = "Tara Wetsover" - , _amznref = "B072BLVM83" - } - ] - } - , Person { _name = "Stephen King" - , _pic = "https://pbs.twimg.com/profile_images/378800000836981162/b683f7509ec792c3e481ead332940cdc_400x400.jpeg" - , _twitter = "StephenKing" - , _blurb = "World renowned Author" - , _website = "https://stephenking.com/" - , _books = [ Book { _title = "Red Moon" - , _author = "Benjamin Percy" - , _amznref = "B008TU2592" - } - , Book { _title = "The Marauders" - , _author = "Tom Cooper" - , _amznref = "B00MKZBVTM" - } - ] - } - , Person { _name = "Tobi Lütke" - , _pic = "https://pbs.twimg.com/profile_images/551403375141457920/28EOlhnM_400x400.jpeg" - , _twitter = "tobi" - , _blurb = "Shopify CEO by day, Dad in the evening, hacker at night. - Rails Core alumni; Author of ActiveMerchant, Liquid. Comprehensivist" - , _website = "https://www.shopify.com" - , _books = [ Book { _title = "Influence" - , _author ="Robert B. Cialdini" - , _amznref = "006124189X" - } - , Book { _title = "High Output Management" - , _author ="Andrew S. Grove" - , _amznref = "B015VACHOK" - } - ] - } - , Person { _name = "Susan Cain" - , _pic = "https://pbs.twimg.com/profile_images/1474290079/SusanCain5smaller-1_400x400.jpg" - , _twitter = "susancain" - , _blurb = "Bestselling author, award-winning speaker, http://Quietrev.com curator. Lover of bittersweet music & bittersweet chocolate, in equal measure." - , _website = "https://www.quietrev.com" - , _books = [ Book { _title = "Bird by Bird" - , _author ="Anne Lamott" - , _amznref = "0385480016" - } - , Book { _title = "Waking Up" - , _author ="Sam Harris" - , _amznref = "1451636024" - } - ] - } - , Person { _name = "Oprah Winfrey" - , _pic = "https://pbs.twimg.com/profile_images/1013835283698049025/q5ZN4yv3_400x400.jpg" - , _twitter = "Oprah" - , _blurb = "Oprah Winfrey is an American media executive, actress, talk show host, television producer and philanthropis" - , _website = "http://www.oprah.com/index.html" - , _books = [ Book { _title = "A New Earth" - , _author ="Eckhart Tolle" - , _amznref = "B000PC0S5K" - } - , Book { _title = "The Poisonwood Bible" - , _author ="Barbara Kingsolver" - , _amznref = "B000QTE9WU" - } - ] - } - , Person { _name = "Patrick Collison" - , _pic = "https://pbs.twimg.com/profile_images/825622525342199809/_iAaSUQf_400x400.jpg" - , _twitter = "patrickc" - , _blurb = "Fallibilist, optimist. Stripe CEO" - , _website = "https://patrickcollison.com" - , _books = [ Book { _title = "How Judges Think" - , _author ="Richard A. Posner" - , _amznref = "0674048067" - } - , Book { _title = "Programmers at Work" - , _author ="Susan Lammers" - , _amznref = "1556152116" - } - ] - } - , Person { _name = "Luis Von Ahn" - , _pic = "https://pbs.twimg.com/profile_images/1020343581087678464/NIXD5MdC_400x400.jpg" - , _twitter = "LuisvonAhn" - , _blurb = "CEO & co-founder of duolingo. Invented reCAPTCHA. Computer science professor at Carnegie Mellon. Proud Guatemalan" - , _website = "https://www.duolingo.com/" - , _books = [ Book { _title = "Zero to One" - , _author ="Peter Thiel" - , _amznref = "B00J6YBOFQ" - } - , Book { _title = "The Hard Thing About Hard Things" - , _author ="Ben Horowitz" - , _amznref = "B00DQ845EA" - } - ] - } - , Person { _name = "Bryan Johnson" - , _pic = "https://pbs.twimg.com/profile_images/1055165076372475904/vNp60sSl_400x400.jpg" - , _twitter = "bryan_johnson" - , _blurb = "Founder of Kernel, OS Fund and Braintree. Trying to go where there is no destination" - , _website = "https://bryanjohnson.co" - , _books = [ Book { _title = "A Good Man" - , _author ="Mark Shriver" - , _amznref = "B007CLBH0M" - } - , Book { _title = "Shackleton" - , _author ="Nick Bertozzi" - , _amznref = "1596434511" - } - ] - } - , Person { _name = "Peter Thiel" - , _pic = "https://pbs.twimg.com/profile_images/1121220551/Peter_Thiel_400x400.jpg" - , _twitter = "peterthiel" - , _blurb = "Technology entrepreneur, investor, philanthropist." - , _website = "http://zerotoonebook.com" - , _books = [ Book { _title = "Deceit, Desire, and the Novel" - , _author ="René Girard" - , _amznref = "0801818303" - } - , Book { _title = "Violence and the Sacred" - , _author ="René Girard" - , _amznref = "0801822181" - } - ] - } - , Person { _name = "Tim Ferris" - , _pic = "https://pbs.twimg.com/profile_images/49918572/half-face-ice_400x400.jpg" - , _twitter = "tferriss" - , _blurb = "Author of 5 #1 NYT/WSJ bestsellers, investor (FB, Uber, Twitter, 50+ more: http://angel.co/tim ), host of The Tim Ferriss Show podcast (300M+ downloads)" - , _website = "http://tim.blog" - , _books = [ Book { _title = "10% Happier" - , _author ="Dan Harris" - , _amznref = "0062265431" - } - , Book { _title = "A Guide to the Good Life" - , _author ="William Irvine" - , _amznref = "B0040JHNQG" - } - ] - } - , Person { _name = "Allen Walton" - , _pic = "https://pbs.twimg.com/profile_images/1038905908678545409/yUbF9Ruc_400x400.jpg" - , _twitter = "allenthird" - , _blurb = "Created http://SpyGuy.com and blogs about stuff at http://AllenWalton.com . All things ecommerce, personal dev, and Simpsons." - , _website = "https://www.allenwalton.com" - , _books = [ Book { _title = "4 Hour Work Week" - , _author ="Tim Ferris" - , _amznref = "B002WE46UW" - } - , Book { _title = "Choose Yourself" - , _author ="James Altucher" - , _amznref = "B00CO8D3G4" - } - ] - } - , Person { _name = "Peter Mallouk" - , _pic = "https://pbs.twimg.com/profile_images/713172266968715264/KsyDYghf_400x400.jpg" - , _twitter = "PeterMallouk" - , _blurb = "President of Creative Planning. Author “5 Mistakes Every Investor Makes & How to Avoid Them”. Radically moderate." - , _website = "https://creativeplanning.com" - , _books = [ Book { _title = "Awareness" - , _author ="Anthony de Mello SJ" - , _amznref = "B005GFBP6W" - } - , Book { _title = "The Prophet" - , _author ="Kahlil Gibran" - , _amznref = "B07NDJ3LMW" - } - ] - } - , Person { _name = "Adam Robinson" - , _pic = "https://pbs.twimg.com/profile_images/822708907051077632/y5KyboMV_400x400.jpg" - , _twitter = "IAmAdamRobinson" - , _blurb = "Entrepreneur. Systems builder. Wizard. Shaman of global financial markets. Manifester. Didact. Do-gooder. Alchemist. Aphorist. Seeker. Embracer of possibility." - , _website = "http://robinsonglobalstrategies.com" - , _books = [ Book { _title = "Wishcraft" - , _author ="Barbara Sher" - , _amznref = "0345465180" - } - , Book { _title = "You Can Be a Stock Market Genius" - , _author ="Joel Greenblatt" - , _amznref = "0684832135" - } - ] - } - , Person { _name = "Andrew Weil" - , _pic = "https://pbs.twimg.com/profile_images/987461787422359553/mpoZAmPH_400x400.jpg" - , _twitter = "DrWeil" - , _blurb = "A world-renowned leader and pioneer in the field of integrative medicine, a healing oriented approach to health care which encompasses body, mind, and spirit." - , _website = "https://www.drweil.com" - , _books = [ Book { _title = "The Way Of Life According To Lao Tzu" - , _author = "Witter Byner" - , _amznref = "0399512985" - } - , Book { _title = "The Psychology of Romantic Love" - , _author ="Nathaniel Branden" - , _amznref = "B0012RMVJI" - } - ] - } - , Person { _name = "Hubert Joly" - , _pic = "https://scontent-ort2-2.xx.fbcdn.net/v/t1.0-1/c1.0.193.193a/38444401_2156120597936470_9028564067043770368_n.jpg?_nc_cat=104&_nc_ht=scontent-ort2-2.xx&oh=162142edb167f389a5b585a329e4993a&oe=5CE1D578" - , _twitter = "BBYCEO" - , _blurb = "CEO of Best Buy" - , _website = "https://www.bestbuy.com" - , _books = [ Book { _title = "Who Says Elephants Can't Dance" - , _author = "Louis. V. Gerstner" - , _amznref = "0060523808" - } - , Book { _title = "Onward" - , _author ="Howard Schultz" - , _amznref = "1609613821" - } - ] - } - , Person { _name = "Esther Perel" - , _pic = "https://pbs.twimg.com/profile_images/1091062675151319040/MzxCcgdU_400x400.jpg" - , _twitter = "EstherPerel" - , _blurb = "Exploring modern relationships. Author of MatingInCaptivity and TheStateOfAffairsBook. Podcast: WhereShouldWeBegin. Psychotherapist in NYC." - , _website = "https://www.estherperel.com" - , _books = [ Book { _title = "Crime And Punishment" - , _author = "Fyodor Dostoyevsky" - , _amznref = "B07NL94DFD" - } - , Book { _title = "If This Is a Man and The Truce" - , _author ="Primo Levi" - , _amznref = "0349100136" - } - ] - } - , Person { _name ="Neil deGrasse Tyson" - , _pic = "https://pbs.twimg.com/profile_images/74188698/NeilTysonOriginsA-Crop_400x400.jpg" - , _twitter = "neiltyson" - , _blurb = "Astrophysicistthe. Fifth head since 1935 of the world-renowned Hayden Planetarium in New York City and the first occupant of its Frederick P. Rose Directorship. Research associate of the Department of Astrophysics at the American Museum of Natural History." - , _website = "https://www.haydenplanetarium.org/tyson/" - , _books = [ Book { _title = "The Prince" - , _author = "Machiavelli" - , _amznref = "B07ND3CM16" - } - , Book { _title = "The Art of War" - , _author ="Sun Tzu" - , _amznref = "1545211957" - } - ] - } - , Person { _name = "Mark Cuban" - , _pic = "https://pbs.twimg.com/profile_images/1422637130/mccigartrophy_400x400.jpg" - , _twitter = "mcuban" - , _blurb = "Owner of Dallas Mavericks, Shark on ABC’s Shark Tank, chairman and CEO of AXS tv, and investor in an ever-growing portfolio of businesses" - , _website = "http://markcubancompanies.com/" - , _books = [ Book { _title = "The Fountainhead" - , _author = "Ayn Rend" - , _amznref = "0452273331" - } - , Book { _title = "The Gospel of Wealth " - , _author ="Andrew Carnegie" - , _amznref = "1409942171" - } - ] - } - , Person { _name = "Robert Herjavec" - , _pic = "https://pbs.twimg.com/profile_images/608643660876423170/DgxUW3eZ_400x400.jpg" - , _twitter = "robertherjavec" - , _blurb = "Dad, Husband, Founder & CEO of global cybersecurity firm HerjavecGroup, Shark on ABC’s Shark Tank, Former Dragon, Author" - , _website = "https://www.robertherjavec.com/" - , _books = [ Book { _title = "Why I Run" - , _author = "Mark Sutcliffe" - , _amznref = "B007OC9P3A" - } - , Book { _title = "Swim with the Sharks Without Being Eaten Alive" - , _author ="Harvey B. Mackay" - , _amznref = "006074281X" - } - ] - } - , Person { _name = "Caterina Fake" - , _pic = "https://pbs.twimg.com/profile_images/378800000509318185/d968d62d1bc39f2c82d3fa44db478525_400x400.jpeg" - , _twitter = "Caterina" - , _blurb = "Host, Should this Exist? Investor, Yes VC. Cofounder: Flickr, Hunch, Sesat School. Etsy. Sundance. Homeschooling, film, literature. Dogs." - , _website = "https://caterina.net" - , _books = [ Book { _title = "Growth of the Soil" - , _author = "Knut Hamsun" - , _amznref = "0343181967" - } - , Book { _title = "The Thousand Autumns of Jacob de Zoet" - , _author ="David Mitchell" - , _amznref = "0812976363" - } - ] - } - , Person { _name = "Daymond John" - , _pic = "https://pbs.twimg.com/profile_images/1048022980863954944/eZvGANn0_400x400.jpg" - , _twitter = "TheSharkDaymond" - , _blurb = "CEO of FUBU, Shark on ABC’s Shark Tank, Author." - , _website = "https://daymondjohn.com/" - , _books = [ Book { _title = "Think and Grow Rich" - , _author = "Napoleon Hill" - , _amznref = "1585424331" - } - , Book { _title = "How to Win Friends & Influence People" - , _author ="Dale Carnegie" - , _amznref = "0671027034" - } - ] - } - , Person { _name = "Kevin O'Leary" - , _pic = "https://pbs.twimg.com/profile_images/1067383195597889536/cP6tNEt0_400x400.jpg" - , _twitter = "kevinolearytv" - , _blurb = "Chairman O'Shares ETFs, 4 time Emmy Award winning Shark Tank's Mr. Wonderful, bestselling author, CNBC contributor, wine maker, guitar dude and photographer." - , _website = "http://askmrwonderful.eone.libsynpro.com/" - , _books = [ Book { _title = "Competitive Advantage" - , _author = "Michael Porter" - , _amznref = "0684841460" - } - , Book { _title = "Secrets of Closing the Sale" - , _author ="Zig Ziglar" - , _amznref = "0425081028" - } - ] - } - , Person { _name = "Alex Rodriguez" - , _pic = "https://pbs.twimg.com/profile_images/796405335388848128/LbvsjCA3_400x400.jpg" - , _twitter = "AROD" - , _blurb = "3-time MVP • 14-time All Star • World Series Champ • CEO of @_ARodCorp• @FoxSports Commentator/Analyst • Special Advisor to the Yankees, @ABCSharkTank and ESPN" - , _website = "http://www.arodcorp.com/" - , _books = [ Book { _title = "Blitzscaling" - , _author = "Reid Hoffman" - , _amznref = "1524761419" - } - , Book { _title = "Measure What Matters" - , _author ="John Doerr" - , _amznref = "0525536221" - } - ] - } + [ Person + { _name = "Joe Rogan", + _pic = "https://pbs.twimg.com/profile_images/552307347851210752/vrXDcTFC_400x400.jpeg", + _twitter = "joerogan", + _blurb = "Stand up comic/mixed martial arts fanatic/psychedelic adventurer Host of The Joe Rogan Experience", + _website = "http://joerogan.com", + _books = + [ Book + { _title = "Food of the Gods", + _author = "Terence McKenna", + _amznref = "0553371304" + }, + Book + { _title = "The War of Art", + _author = "Steven Pressfield", + _amznref = "B007A4SDCG" + } + ] + }, + Person + { _name = "Beyoncé", + _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTxT84sF19lxdnSiblIXAp-Y4wAigpQn8sZ2GtAerIR_ApiiEJfFQ", + _twitter = "Beyonce", + _blurb = "American singer, songwriter, actress, record producer and dancer", + _website = "http://beyonce.com", + _books = + [ Book + { _title = "What Will It Take To Make A Woman President?", + _author = "Marianne Schnall", + _amznref = "B00E257Y7G" + } + ] + }, + Person + { _name = "Barrack Obama", + _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQeLzftR36p0hYI-EKNa5fm7CYDuN-vyz23_R48ocqa8X1nPr6C", + _twitter = "BarackObama", + _blurb = "Dad, husband, President, citizen. 44th POTUS", + _website = "http://barackobama.com", + _books = + [ Book + { _title = "An American Marriage", + _author = "Tayari Jones", + _amznref = "B01NCUXEFR" + }, + Book + { _title = "Americanah", + _author = "Chimamanda Ngozi Adichie", + _amznref = "B00A9ET4MC" + } + ] + }, + Person + { _name = "Warren Buffet", + _pic = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQQbmnUykS6zqgzaf44tsq1RAsnHe6H7fapEoSqUwAoJGSFKbAPSw", + _twitter = "WarrenBuffett", + _blurb = "Chairman and CEO of Berkshire Hathaway", + _website = "http://berkshirehathaway.com", + _books = + [ Book + { _title = "The Intelligent Investor", + _author = "Benjamin Graham", + _amznref = "B000FC12C8" + }, + Book + { _title = "Security Analysis", + _author = "Benjamin Graham", + _amznref = "B0037JO5J8" + } + ] + }, + Person + { _name = "Bill Gates", + _pic = "https://pbs.twimg.com/profile_images/988775660163252226/XpgonN0X_400x400.jpg", + _twitter = "BillGates", + _blurb = "Sharing things I'm learning through my foundation work and other interests. Founder of Microsoft and Bill & Melinda Gates Foundation", + _website = "https://www.gatesnotes.com", + _books = + [ Book + { _title = "Leonardo da Vinci", + _author = "Walter Isaacson", + _amznref = "1501139169" + }, + Book + { _title = "Educated", + _author = "Tara Wetsover", + _amznref = "B072BLVM83" + } + ] + }, + Person + { _name = "Stephen King", + _pic = "https://pbs.twimg.com/profile_images/378800000836981162/b683f7509ec792c3e481ead332940cdc_400x400.jpeg", + _twitter = "StephenKing", + _blurb = "World renowned Author", + _website = "https://stephenking.com/", + _books = + [ Book + { _title = "Red Moon", + _author = "Benjamin Percy", + _amznref = "B008TU2592" + }, + Book + { _title = "The Marauders", + _author = "Tom Cooper", + _amznref = "B00MKZBVTM" + } + ] + }, + Person + { _name = "Tobi Lütke", + _pic = "https://pbs.twimg.com/profile_images/551403375141457920/28EOlhnM_400x400.jpeg", + _twitter = "tobi", + _blurb = "Shopify CEO by day, Dad in the evening, hacker at night. - Rails Core alumni; Author of ActiveMerchant, Liquid. Comprehensivist", + _website = "https://www.shopify.com", + _books = + [ Book + { _title = "Influence", + _author = "Robert B. Cialdini", + _amznref = "006124189X" + }, + Book + { _title = "High Output Management", + _author = "Andrew S. Grove", + _amznref = "B015VACHOK" + } + ] + }, + Person + { _name = "Susan Cain", + _pic = "https://pbs.twimg.com/profile_images/1474290079/SusanCain5smaller-1_400x400.jpg", + _twitter = "susancain", + _blurb = "Bestselling author, award-winning speaker, http://Quietrev.com curator. Lover of bittersweet music & bittersweet chocolate, in equal measure.", + _website = "https://www.quietrev.com", + _books = + [ Book + { _title = "Bird by Bird", + _author = "Anne Lamott", + _amznref = "0385480016" + }, + Book + { _title = "Waking Up", + _author = "Sam Harris", + _amznref = "1451636024" + } + ] + }, + Person + { _name = "Oprah Winfrey", + _pic = "https://pbs.twimg.com/profile_images/1013835283698049025/q5ZN4yv3_400x400.jpg", + _twitter = "Oprah", + _blurb = "Oprah Winfrey is an American media executive, actress, talk show host, television producer and philanthropis", + _website = "http://www.oprah.com/index.html", + _books = + [ Book + { _title = "A New Earth", + _author = "Eckhart Tolle", + _amznref = "B000PC0S5K" + }, + Book + { _title = "The Poisonwood Bible", + _author = "Barbara Kingsolver", + _amznref = "B000QTE9WU" + } + ] + }, + Person + { _name = "Patrick Collison", + _pic = "https://pbs.twimg.com/profile_images/825622525342199809/_iAaSUQf_400x400.jpg", + _twitter = "patrickc", + _blurb = "Fallibilist, optimist. Stripe CEO", + _website = "https://patrickcollison.com", + _books = + [ Book + { _title = "How Judges Think", + _author = "Richard A. Posner", + _amznref = "0674048067" + }, + Book + { _title = "Programmers at Work", + _author = "Susan Lammers", + _amznref = "1556152116" + } + ] + }, + Person + { _name = "Luis Von Ahn", + _pic = "https://pbs.twimg.com/profile_images/1020343581087678464/NIXD5MdC_400x400.jpg", + _twitter = "LuisvonAhn", + _blurb = "CEO & co-founder of duolingo. Invented reCAPTCHA. Computer science professor at Carnegie Mellon. Proud Guatemalan", + _website = "https://www.duolingo.com/", + _books = + [ Book + { _title = "Zero to One", + _author = "Peter Thiel", + _amznref = "B00J6YBOFQ" + }, + Book + { _title = "The Hard Thing About Hard Things", + _author = "Ben Horowitz", + _amznref = "B00DQ845EA" + } + ] + }, + Person + { _name = "Bryan Johnson", + _pic = "https://pbs.twimg.com/profile_images/1055165076372475904/vNp60sSl_400x400.jpg", + _twitter = "bryan_johnson", + _blurb = "Founder of Kernel, OS Fund and Braintree. Trying to go where there is no destination", + _website = "https://bryanjohnson.co", + _books = + [ Book + { _title = "A Good Man", + _author = "Mark Shriver", + _amznref = "B007CLBH0M" + }, + Book + { _title = "Shackleton", + _author = "Nick Bertozzi", + _amznref = "1596434511" + } + ] + }, + Person + { _name = "Peter Thiel", + _pic = "https://pbs.twimg.com/profile_images/1121220551/Peter_Thiel_400x400.jpg", + _twitter = "peterthiel", + _blurb = "Technology entrepreneur, investor, philanthropist.", + _website = "http://zerotoonebook.com", + _books = + [ Book + { _title = "Deceit, Desire, and the Novel", + _author = "René Girard", + _amznref = "0801818303" + }, + Book + { _title = "Violence and the Sacred", + _author = "René Girard", + _amznref = "0801822181" + } + ] + }, + Person + { _name = "Tim Ferris", + _pic = "https://pbs.twimg.com/profile_images/49918572/half-face-ice_400x400.jpg", + _twitter = "tferriss", + _blurb = "Author of 5 #1 NYT/WSJ bestsellers, investor (FB, Uber, Twitter, 50+ more: http://angel.co/tim ), host of The Tim Ferriss Show podcast (300M+ downloads)", + _website = "http://tim.blog", + _books = + [ Book + { _title = "10% Happier", + _author = "Dan Harris", + _amznref = "0062265431" + }, + Book + { _title = "A Guide to the Good Life", + _author = "William Irvine", + _amznref = "B0040JHNQG" + } + ] + }, + Person + { _name = "Allen Walton", + _pic = "https://pbs.twimg.com/profile_images/1038905908678545409/yUbF9Ruc_400x400.jpg", + _twitter = "allenthird", + _blurb = "Created http://SpyGuy.com and blogs about stuff at http://AllenWalton.com . All things ecommerce, personal dev, and Simpsons.", + _website = "https://www.allenwalton.com", + _books = + [ Book + { _title = "4 Hour Work Week", + _author = "Tim Ferris", + _amznref = "B002WE46UW" + }, + Book + { _title = "Choose Yourself", + _author = "James Altucher", + _amznref = "B00CO8D3G4" + } + ] + }, + Person + { _name = "Peter Mallouk", + _pic = "https://pbs.twimg.com/profile_images/713172266968715264/KsyDYghf_400x400.jpg", + _twitter = "PeterMallouk", + _blurb = "President of Creative Planning. Author “5 Mistakes Every Investor Makes & How to Avoid Them”. Radically moderate.", + _website = "https://creativeplanning.com", + _books = + [ Book + { _title = "Awareness", + _author = "Anthony de Mello SJ", + _amznref = "B005GFBP6W" + }, + Book + { _title = "The Prophet", + _author = "Kahlil Gibran", + _amznref = "B07NDJ3LMW" + } + ] + }, + Person + { _name = "Adam Robinson", + _pic = "https://pbs.twimg.com/profile_images/822708907051077632/y5KyboMV_400x400.jpg", + _twitter = "IAmAdamRobinson", + _blurb = "Entrepreneur. Systems builder. Wizard. Shaman of global financial markets. Manifester. Didact. Do-gooder. Alchemist. Aphorist. Seeker. Embracer of possibility.", + _website = "http://robinsonglobalstrategies.com", + _books = + [ Book + { _title = "Wishcraft", + _author = "Barbara Sher", + _amznref = "0345465180" + }, + Book + { _title = "You Can Be a Stock Market Genius", + _author = "Joel Greenblatt", + _amznref = "0684832135" + } + ] + }, + Person + { _name = "Andrew Weil", + _pic = "https://pbs.twimg.com/profile_images/987461787422359553/mpoZAmPH_400x400.jpg", + _twitter = "DrWeil", + _blurb = "A world-renowned leader and pioneer in the field of integrative medicine, a healing oriented approach to health care which encompasses body, mind, and spirit.", + _website = "https://www.drweil.com", + _books = + [ Book + { _title = "The Way Of Life According To Lao Tzu", + _author = "Witter Byner", + _amznref = "0399512985" + }, + Book + { _title = "The Psychology of Romantic Love", + _author = "Nathaniel Branden", + _amznref = "B0012RMVJI" + } + ] + }, + Person + { _name = "Hubert Joly", + _pic = "https://scontent-ort2-2.xx.fbcdn.net/v/t1.0-1/c1.0.193.193a/38444401_2156120597936470_9028564067043770368_n.jpg?_nc_cat=104&_nc_ht=scontent-ort2-2.xx&oh=162142edb167f389a5b585a329e4993a&oe=5CE1D578", + _twitter = "BBYCEO", + _blurb = "CEO of Best Buy", + _website = "https://www.bestbuy.com", + _books = + [ Book + { _title = "Who Says Elephants Can't Dance", + _author = "Louis. V. Gerstner", + _amznref = "0060523808" + }, + Book + { _title = "Onward", + _author = "Howard Schultz", + _amznref = "1609613821" + } + ] + }, + Person + { _name = "Esther Perel", + _pic = "https://pbs.twimg.com/profile_images/1091062675151319040/MzxCcgdU_400x400.jpg", + _twitter = "EstherPerel", + _blurb = "Exploring modern relationships. Author of MatingInCaptivity and TheStateOfAffairsBook. Podcast: WhereShouldWeBegin. Psychotherapist in NYC.", + _website = "https://www.estherperel.com", + _books = + [ Book + { _title = "Crime And Punishment", + _author = "Fyodor Dostoyevsky", + _amznref = "B07NL94DFD" + }, + Book + { _title = "If This Is a Man and The Truce", + _author = "Primo Levi", + _amznref = "0349100136" + } + ] + }, + Person + { _name = "Neil deGrasse Tyson", + _pic = "https://pbs.twimg.com/profile_images/74188698/NeilTysonOriginsA-Crop_400x400.jpg", + _twitter = "neiltyson", + _blurb = "Astrophysicistthe. Fifth head since 1935 of the world-renowned Hayden Planetarium in New York City and the first occupant of its Frederick P. Rose Directorship. Research associate of the Department of Astrophysics at the American Museum of Natural History.", + _website = "https://www.haydenplanetarium.org/tyson/", + _books = + [ Book + { _title = "The Prince", + _author = "Machiavelli", + _amznref = "B07ND3CM16" + }, + Book + { _title = "The Art of War", + _author = "Sun Tzu", + _amznref = "1545211957" + } + ] + }, + Person + { _name = "Mark Cuban", + _pic = "https://pbs.twimg.com/profile_images/1422637130/mccigartrophy_400x400.jpg", + _twitter = "mcuban", + _blurb = "Owner of Dallas Mavericks, Shark on ABC’s Shark Tank, chairman and CEO of AXS tv, and investor in an ever-growing portfolio of businesses", + _website = "http://markcubancompanies.com/", + _books = + [ Book + { _title = "The Fountainhead", + _author = "Ayn Rend", + _amznref = "0452273331" + }, + Book + { _title = "The Gospel of Wealth ", + _author = "Andrew Carnegie", + _amznref = "1409942171" + } + ] + }, + Person + { _name = "Robert Herjavec", + _pic = "https://pbs.twimg.com/profile_images/608643660876423170/DgxUW3eZ_400x400.jpg", + _twitter = "robertherjavec", + _blurb = "Dad, Husband, Founder & CEO of global cybersecurity firm HerjavecGroup, Shark on ABC’s Shark Tank, Former Dragon, Author", + _website = "https://www.robertherjavec.com/", + _books = + [ Book + { _title = "Why I Run", + _author = "Mark Sutcliffe", + _amznref = "B007OC9P3A" + }, + Book + { _title = "Swim with the Sharks Without Being Eaten Alive", + _author = "Harvey B. Mackay", + _amznref = "006074281X" + } + ] + }, + Person + { _name = "Caterina Fake", + _pic = "https://pbs.twimg.com/profile_images/378800000509318185/d968d62d1bc39f2c82d3fa44db478525_400x400.jpeg", + _twitter = "Caterina", + _blurb = "Host, Should this Exist? Investor, Yes VC. Cofounder: Flickr, Hunch, Sesat School. Etsy. Sundance. Homeschooling, film, literature. Dogs.", + _website = "https://caterina.net", + _books = + [ Book + { _title = "Growth of the Soil", + _author = "Knut Hamsun", + _amznref = "0343181967" + }, + Book + { _title = "The Thousand Autumns of Jacob de Zoet", + _author = "David Mitchell", + _amznref = "0812976363" + } + ] + }, + Person + { _name = "Daymond John", + _pic = "https://pbs.twimg.com/profile_images/1048022980863954944/eZvGANn0_400x400.jpg", + _twitter = "TheSharkDaymond", + _blurb = "CEO of FUBU, Shark on ABC’s Shark Tank, Author.", + _website = "https://daymondjohn.com/", + _books = + [ Book + { _title = "Think and Grow Rich", + _author = "Napoleon Hill", + _amznref = "1585424331" + }, + Book + { _title = "How to Win Friends & Influence People", + _author = "Dale Carnegie", + _amznref = "0671027034" + } + ] + }, + Person + { _name = "Kevin O'Leary", + _pic = "https://pbs.twimg.com/profile_images/1067383195597889536/cP6tNEt0_400x400.jpg", + _twitter = "kevinolearytv", + _blurb = "Chairman O'Shares ETFs, 4 time Emmy Award winning Shark Tank's Mr. Wonderful, bestselling author, CNBC contributor, wine maker, guitar dude and photographer.", + _website = "http://askmrwonderful.eone.libsynpro.com/", + _books = + [ Book + { _title = "Competitive Advantage", + _author = "Michael Porter", + _amznref = "0684841460" + }, + Book + { _title = "Secrets of Closing the Sale", + _author = "Zig Ziglar", + _amznref = "0425081028" + } + ] + }, + Person + { _name = "Alex Rodriguez", + _pic = "https://pbs.twimg.com/profile_images/796405335388848128/LbvsjCA3_400x400.jpg", + _twitter = "AROD", + _blurb = "3-time MVP • 14-time All Star • World Series Champ • CEO of @_ARodCorp• @FoxSports Commentator/Analyst • Special Advisor to the Yankees, @ABCSharkTank and ESPN", + _website = "http://www.arodcorp.com/", + _books = + [ Book + { _title = "Blitzscaling", + _author = "Reid Hoffman", + _amznref = "1524761419" + }, + Book + { _title = "Measure What Matters", + _author = "John Doerr", + _amznref = "0525536221" + } + ] + } ] diff --git a/Biz/Ibb/Keep.hs b/Biz/Ibb/Keep.hs index ad6dc5c..d546aae 100644 --- a/Biz/Ibb/Keep.hs +++ b/Biz/Ibb/Keep.hs @@ -1,6 +1,6 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -9,68 +9,74 @@ -- If this proves useful, maybe we could make it a more general thing. Like -- `Biz.Keep`. I could wrap all the safecopy stuff in my own template haskell -- like `$(keep ''MyType)`. --- module Biz.Ibb.Keep where -import Biz.Ibb.Core (Person(..), Book(..)) +import Biz.Ibb.Core (Book (..), Person (..)) import qualified Biz.Ibb.Influencers as Influencers -import Control.Monad.Reader (ask) -import Control.Monad.State (get, put) -import Data.Acid (Update, makeAcidic) +import Control.Monad.Reader (ask) +import Control.Monad.State (get, put) +import Data.Acid (Update, makeAcidic) import qualified Data.Acid as Acid -import Data.Data (Data, Typeable) -import Data.IxSet (Indexable(..), IxSet, ixFun, ixSet) +import Data.Data (Data, Typeable) +import Data.IxSet (Indexable (..), IxSet, ixFun, ixSet) import qualified Data.IxSet as IxSet -import Data.SafeCopy -import Data.Text (Text) +import Data.SafeCopy +import Data.Text (Text) import qualified Data.Text as Text -- * Keep -- | Main database. Need to think of a better name for this. -data IbbKeep = IbbKeep - { _people :: IxSet Person - } +data IbbKeep + = IbbKeep + { _people :: IxSet Person + } deriving (Data, Typeable) $(deriveSafeCopy 0 'base ''IbbKeep) -- * Index @Person@ -$(deriveSafeCopy 0 'base ''Person) +$(deriveSafeCopy 0 'base ''Person) -newtype PersonName = - PersonName Text deriving (Eq, Ord, Data, Typeable) +newtype PersonName + = PersonName Text + deriving (Eq, Ord, Data, Typeable) -newtype PersonBlurb = - PersonBlurb Text deriving (Eq, Ord, Data, Typeable) +newtype PersonBlurb + = PersonBlurb Text + deriving (Eq, Ord, Data, Typeable) instance Indexable Person where - empty = ixSet - [ ixFun $ \p -> [ PersonName $ _name p ] - , ixFun $ \p -> [ _pic p ] - , ixFun $ \p -> [ _twitter p ] - , ixFun $ \p -> [ _website p ] - , ixFun $ \p -> [ _books p ] - , ixFun $ \p -> [ PersonBlurb $ _blurb p ] - ] + empty = + ixSet + [ ixFun $ \p -> [PersonName $ _name p], + ixFun $ \p -> [_pic p], + ixFun $ \p -> [_twitter p], + ixFun $ \p -> [_website p], + ixFun $ \p -> [_books p], + ixFun $ \p -> [PersonBlurb $ _blurb p] + ] -- | updates the `IbbKeep` with a new `Person` newPerson :: Text -> Text -> Update IbbKeep Person newPerson name blurb = do k <- get - put $ k { _people = IxSet.insert p (_people k) - } + put $ + k + { _people = IxSet.insert p (_people k) + } return p - where - p = Person - { _name = name - , _pic = Text.empty - , _twitter = Text.empty - , _website = Text.empty - , _books = [] - , _blurb = blurb - } + where + p = + Person + { _name = name, + _pic = Text.empty, + _twitter = Text.empty, + _website = Text.empty, + _books = [], + _blurb = blurb + } getPeople :: Int -> Acid.Query IbbKeep [Person] getPeople n = do @@ -79,24 +85,27 @@ getPeople n = do -- * Index @Book@ -$(deriveSafeCopy 0 'base ''Book) +$(deriveSafeCopy 0 'base ''Book) -newtype BookTitle = - BookTitle Text deriving (Eq, Ord, Data, Typeable) +newtype BookTitle + = BookTitle Text + deriving (Eq, Ord, Data, Typeable) -newtype BookAuthor = - BookAuthor Text deriving (Eq, Ord, Data, Typeable) +newtype BookAuthor + = BookAuthor Text + deriving (Eq, Ord, Data, Typeable) instance Indexable Book where - empty = ixSet - [ ixFun $ \b -> [ BookTitle $ _title b ] - , ixFun $ \b -> [ BookAuthor $ _author b ] - , ixFun $ \b -> [ _amznref b ] - ] + empty = + ixSet + [ ixFun $ \b -> [BookTitle $ _title b], + ixFun $ \b -> [BookAuthor $ _author b], + ixFun $ \b -> [_amznref b] + ] -- | updates the `IbbKeep` with a new `Book` ---newBook :: Text -> Text -> Text -> Update IbbKeep Book ---newBook title author amznref = do +-- newBook :: Text -> Text -> Text -> Update IbbKeep Book +-- newBook title author amznref = do -- ibbKeep <- get -- put $ ibbKeep { _books = IxSet.insert b (_books ibbKeep) -- , _people = _people ibbKeep @@ -114,9 +123,10 @@ instance Indexable Book where $(makeAcidic ''IbbKeep ['newPerson, 'getPeople]) initialIbbKeep :: IbbKeep -initialIbbKeep = IbbKeep - { _people = IxSet.fromList Influencers.allPeople - } +initialIbbKeep = + IbbKeep + { _people = IxSet.fromList Influencers.allPeople + } openLocal :: String -> IO (Acid.AcidState IbbKeep) openLocal dir = diff --git a/Biz/Ibb/Look.hs b/Biz/Ibb/Look.hs index 5f7ca6b..1ab12c1 100644 --- a/Biz/Ibb/Look.hs +++ b/Biz/Ibb/Look.hs @@ -4,12 +4,12 @@ -- | The look and feel of Ibb module Biz.Ibb.Look where -import Alpha hiding ( Selector ) -import Clay -import qualified Clay.Flexbox as Flexbox -import qualified Clay.Media as Media -import qualified Clay.Render as Clay -import qualified Clay.Stylesheet as Stylesheet +import Alpha hiding (Selector) +import Clay +import qualified Clay.Flexbox as Flexbox +import qualified Clay.Media as Media +import qualified Clay.Render as Clay +import qualified Clay.Stylesheet as Stylesheet main :: Css main = do @@ -28,11 +28,11 @@ main = do fontFamily ["GillSans", "Calibri", "Trebuchet"] [sansSerif] headings ? do fontFamily - [ "Palatino" - , "Palatino Linotype" - , "Hoefler Text" - , "Times New Roman" - , "Times" + [ "Palatino", + "Palatino Linotype", + "Hoefler Text", + "Times New Roman", + "Times" ] [serif] diff --git a/Biz/Ibb/Move.hs b/Biz/Ibb/Move.hs index 1e635ac..0dec4e5 100644 --- a/Biz/Ibb/Move.hs +++ b/Biz/Ibb/Move.hs @@ -1,34 +1,36 @@ -{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE NoImplicitPrelude #-} -- | App update logic module Biz.Ibb.Move - ( move - -- * Server interactions - , fetchPeople + ( move, + + -- * Server interactions + fetchPeople, ) where -import Alpha -import Biz.Ibb.Core as Core -import Network.RemoteData -import Data.Aeson -import JavaScript.Web.XMLHttpRequest ( Request(..) - , Method(GET) - , RequestData(NoData) - , contents - , xhrByteString - ) -import Miso -import Miso.String +import Alpha +import Biz.Ibb.Core as Core +import Data.Aeson +import JavaScript.Web.XMLHttpRequest + ( Method (GET), + Request (..), + RequestData (NoData), + contents, + xhrByteString, + ) +import Miso +import Miso.String +import Network.RemoteData move :: Action -> Model -> Effect Action Model -move Nop m = noEff m -move (HandleRoute u) m = m { uri = u } <# pure Nop +move Nop m = noEff m +move (HandleRoute u) m = m {uri = u} <# pure Nop move (ChangeRoute u) m = m <# do pushURI u >> pure Nop -move FetchPeople m = m <# (SetPeople pure $ Failure "could not read from server" Just a -> pure $ fromEither $ either (Left . ms) pure $ eitherDecodeStrict a - where - req = Request { reqMethod = GET - -- FIXME: can replace this hardcoding with a function? - , reqURI = "/api/people" - , reqLogin = Nothing - , reqHeaders = [] - , reqWithCredentials = False - , reqData = NoData - } + where + req = + Request + { reqMethod = GET, + -- FIXME: can replace this hardcoding with a function? + reqURI = "/api/people", + reqLogin = Nothing, + reqHeaders = [], + reqWithCredentials = False, + reqData = NoData + } diff --git a/Biz/Ibb/Server.hs b/Biz/Ibb/Server.hs index 9f1ac5f..b5a7464 100644 --- a/Biz/Ibb/Server.hs +++ b/Biz/Ibb/Server.hs @@ -1,11 +1,11 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} +{-# LANGUAGE NoImplicitPrelude #-} -- | Server -- @@ -27,41 +27,43 @@ -- : dep text module Biz.Ibb.Server where -import Alpha +import Alpha +import Biz.Ibb.Core +import qualified Biz.Ibb.Keep as Keep +import qualified Biz.Ibb.Look as Look import qualified Clay -import Biz.Ibb.Core -import qualified Biz.Ibb.Keep as Keep -import qualified Biz.Ibb.Look as Look -import Network.RemoteData -import Data.Acid ( AcidState ) -import qualified Data.Acid.Abstract as Acid -import Data.Maybe ( fromMaybe ) -import qualified Data.Text.Lazy as Lazy -import qualified Data.Text.Lazy.Encoding as Lazy -import qualified Lucid as L -import Lucid.Base -import Miso -import Network.HTTP.Media ( (//) - , (/:) - ) -import Network.HTTP.Types -import Network.Wai -import Network.Wai.Application.Static -import Network.Wai.Handler.Warp -import Network.Wai.Middleware.Gzip -import Network.Wai.Middleware.RequestLogger -import Servant -import System.Environment ( lookupEnv ) +import Data.Acid (AcidState) +import qualified Data.Acid.Abstract as Acid +import Data.Maybe (fromMaybe) +import qualified Data.Text.Lazy as Lazy +import qualified Data.Text.Lazy.Encoding as Lazy +import qualified Lucid as L +import Lucid.Base +import Miso +import Network.HTTP.Media + ( (//), + (/:), + ) +import Network.HTTP.Types +import Network.RemoteData +import Network.Wai +import Network.Wai.Application.Static +import Network.Wai.Handler.Warp +import Network.Wai.Middleware.Gzip +import Network.Wai.Middleware.RequestLogger +import Servant +import System.Environment (lookupEnv) main :: IO () main = do say "rise: ibb" staticDir <- fromMaybe "static" <$> lookupEnv "STATIC_DIR" :: IO [Char] - port <- read <$> fromMaybe "3000" <$> lookupEnv "PORT" :: IO Int - keep <- Keep.openLocal "_keep/" + port <- read <$> fromMaybe "3000" <$> lookupEnv "PORT" :: IO Int + keep <- Keep.openLocal "_keep/" say "port: 3000" run port $ logStdout $ compress $ app staticDir $ keep - where compress = gzip def { gzipFiles = GzipCompress } + where + compress = gzip def {gzipFiles = GzipCompress} newtype HtmlPage a = HtmlPage a deriving (Show, Eq) @@ -75,18 +77,20 @@ instance L.ToHtml a => L.ToHtml (HtmlPage a) where cssRef "/css/main.css" L.body_ $ do page - where - page = L.toHtml x - jsRef href = L.with - (L.script_ mempty) - [ makeAttribute "src" href - , makeAttribute "type" "text/javascript" - , makeAttribute "async" mempty - , makeAttribute "defer" mempty - ] - cssRef href = L.with - (L.link_ mempty) - [L.rel_ "stylesheet", L.type_ "text/css", L.href_ href] + where + page = L.toHtml x + jsRef href = + L.with + (L.script_ mempty) + [ makeAttribute "src" href, + makeAttribute "type" "text/javascript", + makeAttribute "async" mempty, + makeAttribute "defer" mempty + ] + cssRef href = + L.with + (L.link_ mempty) + [L.rel_ "stylesheet", L.type_ "text/css", L.href_ href] type ServerRoutes = ToServerRoutes AppRoutes HtmlPage Action @@ -99,9 +103,10 @@ handle404 _ respond = $ HtmlPage $ notfound -newtype CSS = CSS - { unCSS :: Text - } +newtype CSS + = CSS + { unCSS :: Text + } instance MimeRender CSS Text where mimeRender _ = Lazy.encodeUtf8 . Lazy.fromStrict @@ -111,41 +116,36 @@ instance Accept CSS where type CssRoute = "css" :> "main.css" :> Get '[CSS] Text -type Routes - = "static" - :> - Raw - :<|> - CssRoute - :<|> - ServerRoutes - :<|> - "api" - :> - ApiRoutes - :<|> - Raw +type Routes = + "static" + :> Raw + :<|> CssRoute + :<|> ServerRoutes + :<|> "api" + :> ApiRoutes + :<|> Raw cssHandlers :: Server CssRoute cssHandlers = return . Lazy.toStrict . Clay.render $ Look.main app :: [Char] -> AcidState Keep.IbbKeep -> Application app staticDir keep = - serve (Proxy @Routes) - $ static - :<|> cssHandlers - :<|> serverHandlers - :<|> apiHandlers keep - :<|> Tagged handle404 - where static = serveDirectoryWith (defaultWebAppSettings $ staticDir) + serve (Proxy @Routes) $ + static + :<|> cssHandlers + :<|> serverHandlers + :<|> apiHandlers keep + :<|> Tagged handle404 + where + static = serveDirectoryWith (defaultWebAppSettings $ staticDir) type ApiRoutes = "people" :> Get '[JSON] [Person] serverHandlers :: Server ServerRoutes serverHandlers = homeHandler - where - send f u = pure $ HtmlPage $ f Model { uri = u, people = NotAsked } - homeHandler = send home goHome + where + send f u = pure $ HtmlPage $ f Model {uri = u, people = NotAsked} + homeHandler = send home goHome -- | for now we just have one api endpoint, which returns all the people apiHandlers :: AcidState Keep.IbbKeep -> Server ApiRoutes diff --git a/Biz/Language/Bs.hs b/Biz/Language/Bs.hs index a810706..f2d4c9d 100644 --- a/Biz/Language/Bs.hs +++ b/Biz/Language/Bs.hs @@ -1,8 +1,9 @@ -- https://github.com/write-you-a-scheme-v2/scheme -- https://github.com/justinethier/husk-scheme module Language.Bs - ( module X - ) where + ( module X, + ) +where import Language.Bs.Cli as X import Language.Bs.Eval as X diff --git a/Biz/Language/Bs/Cli.hs b/Biz/Language/Bs/Cli.hs index 4c48c86..d2ac1e4 100644 --- a/Biz/Language/Bs/Cli.hs +++ b/Biz/Language/Bs/Cli.hs @@ -1,8 +1,10 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} -module Language.Bs.Cli ( - run -) where + +module Language.Bs.Cli + ( run, + ) +where import Data.String import Data.Text.IO as TIO @@ -17,12 +19,12 @@ import System.Directory -- https://github.com/pcapriotti/optparse-applicative -- https://hackage.haskell.org/package/optparse-applicative -runScript :: FilePath -> IO () +runScript :: FilePath -> IO () runScript fname = do exists <- doesFileExist fname if exists - then TIO.readFile fname >>= evalFile fname - else TIO.putStrLn "File does not exist." + then TIO.readFile fname >>= evalFile fname + else TIO.putStrLn "File does not exist." data LineOpts = UseReplLineOpts | RunScriptLineOpts String @@ -30,14 +32,21 @@ parseLineOpts :: Parser LineOpts parseLineOpts = runScriptOpt <|> runReplOpt where runScriptOpt = - RunScriptLineOpts <$> strOption (long "script" - <> short 's' - <> metavar "SCRIPT" - <> help "File containing the script you want to run") + RunScriptLineOpts + <$> strOption + ( long "script" + <> short 's' + <> metavar "SCRIPT" + <> help "File containing the script you want to run" + ) runReplOpt = - UseReplLineOpts <$ flag' () (long "repl" - <> short 'r' - <> help "Run as interavtive read/evaluate/print/loop") + UseReplLineOpts + <$ flag' + () + ( long "repl" + <> short 'r' + <> help "Run as interavtive read/evaluate/print/loop" + ) schemeEntryPoint :: LineOpts -> IO () schemeEntryPoint UseReplLineOpts = mainLoop --repl @@ -46,7 +55,10 @@ schemeEntryPoint (RunScriptLineOpts script) = runScript script run :: IO () run = execParser opts >>= schemeEntryPoint where - opts = info (helper <*> parseLineOpts) - ( fullDesc - <> header "Executable binary for Write You A Scheme v2.0" - <> progDesc "contains an entry point for both running scripts and repl" ) + opts = + info + (helper <*> parseLineOpts) + ( fullDesc + <> header "Executable binary for Write You A Scheme v2.0" + <> progDesc "contains an entry point for both running scripts and repl" + ) diff --git a/Biz/Language/Bs/Eval.hs b/Biz/Language/Bs/Eval.hs index 290170b..1198a3e 100644 --- a/Biz/Language/Bs/Eval.hs +++ b/Biz/Language/Bs/Eval.hs @@ -1,19 +1,21 @@ {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE NoImplicitPrelude #-} -module Language.Bs.Eval ( - evalText -, evalFile -, runParseTest -, safeExec -, runASTinEnv -, basicEnv -, fileToEvalForm -, textToEvalForm -, getFileContents -) where + +module Language.Bs.Eval + ( evalText, + evalFile, + runParseTest, + safeExec, + runASTinEnv, + basicEnv, + fileToEvalForm, + textToEvalForm, + getFileContents, + ) +where import Control.Exception import Control.Monad.Reader @@ -28,23 +30,25 @@ import Protolude import System.Directory funcEnv :: Map.Map T.Text Expr -funcEnv = Map.fromList $ primEnv - <> [ ("read" , IFun $ IFunc $ unop readFn) - , ("parse", IFun $ IFunc $ unop parseFn) - , ("eval", IFun $ IFunc $ unop eval) - , ("show", IFun $ IFunc $ unop (return . Tape . ppexpr)) - ] +funcEnv = + Map.fromList $ + primEnv + <> [ ("read", IFun $ IFunc $ unop readFn), + ("parse", IFun $ IFunc $ unop parseFn), + ("eval", IFun $ IFunc $ unop eval), + ("show", IFun $ IFunc $ unop (return . Tape . ppexpr)) + ] basicEnv :: Env basicEnv = Env Map.empty funcEnv readFn :: Expr -> Eval Expr readFn (Tape txt) = lineToEvalForm txt -readFn val = throw $ TypeMismatch "read expects string, instead got:" val +readFn val = throw $ TypeMismatch "read expects string, instead got:" val parseFn :: Expr -> Eval Expr parseFn (Tape txt) = either (throw . ParseError . show) return $ readExpr txt -parseFn val = throw $ TypeMismatch "parse expects string, instead got:" val +parseFn val = throw $ TypeMismatch "parse expects string, instead got:" val safeExec :: IO a -> IO (Either String a) safeExec m = do @@ -63,13 +67,13 @@ runASTinEnv :: Env -> Eval b -> IO b runASTinEnv code action = runReaderT (unEval action) code lineToEvalForm :: T.Text -> Eval Expr -lineToEvalForm input = either (throw . ParseError . show ) eval $ readExpr input +lineToEvalForm input = either (throw . ParseError . show) eval $ readExpr input evalFile :: FilePath -> T.Text -> IO () -- program file evalFile filePath fileExpr = (runASTinEnv basicEnv $ fileToEvalForm filePath fileExpr) >>= print fileToEvalForm :: FilePath -> T.Text -> Eval Expr -fileToEvalForm filePath input = either (throw . ParseError . show ) evalBody $ readExprFile filePath input +fileToEvalForm filePath input = either (throw . ParseError . show) evalBody $ readExprFile filePath input runParseTest :: T.Text -> T.Text -- for view AST runParseTest input = either (T.pack . show) (T.pack . show) $ readExpr input @@ -77,23 +81,23 @@ runParseTest input = either (T.pack . show) (T.pack . show) $ readExpr input getFileContents :: FilePath -> IO T.Text getFileContents fname = do exists <- doesFileExist fname - if exists then TIO.readFile fname else return "File does not exist." + if exists then TIO.readFile fname else return "File does not exist." textToEvalForm :: T.Text -> Eval Expr -textToEvalForm input = either (throw . ParseError . show ) evalBody $ readExpr input +textToEvalForm input = either (throw . ParseError . show) evalBody $ readExpr input evalText :: T.Text -> IO () --REPL evalText textExpr = do res <- runASTinEnv basicEnv $ textToEvalForm textExpr print res -getVar :: Expr -> Eval Expr +getVar :: Expr -> Eval Expr getVar (Atom atom) = do - Env{..} <- ask + Env {..} <- ask case Map.lookup atom (Map.union fenv env) of -- lookup, but prefer functions - Just x -> return x - Nothing -> throw $ UnboundVar atom -getVar n = throw $ TypeMismatch "failure to get variable: " n + Just x -> return x + Nothing -> throw $ UnboundVar atom +getVar n = throw $ TypeMismatch "failure to get variable: " n ensureAtom :: Expr -> Eval Expr ensureAtom n@(Atom _) = return n @@ -106,136 +110,115 @@ extractVar n = throw $ TypeMismatch "expected an atomic value" n getEven :: [t] -> [t] getEven [] = [] -getEven (x:xs) = x : getOdd xs +getEven (x : xs) = x : getOdd xs getOdd :: [t] -> [t] getOdd [] = [] -getOdd (_:xs) = getEven xs +getOdd (_ : xs) = getEven xs applyFunc :: Expr -> [Expr] -> [Expr] -> Eval Expr applyFunc expr params args = bindArgsEval params args expr bindArgsEval :: [Expr] -> [Expr] -> Expr -> Eval Expr bindArgsEval params args expr = do - Env{..} <- ask - let newVars = zipWith (\a b -> (extractVar a,b)) params args + Env {..} <- ask + let newVars = zipWith (\a b -> (extractVar a, b)) params args let (newEnv, newFenv) = Map.partition (not . isFunc) $ Map.fromList newVars local (const $ Env (newEnv <> env) (newFenv <> fenv)) $ eval expr isFunc :: Expr -> Bool -isFunc (List ((Atom "lambda"):_)) = True -isFunc _ = False +isFunc (List ((Atom "lambda") : _)) = True +isFunc _ = False eval :: Expr -> Eval Expr eval (List [Atom "dumpEnv", x]) = do - Env{..} <- ask + Env {..} <- ask liftIO $ print $ toList env liftIO $ print $ toList fenv eval x - -eval (Numb i) = return $ Numb i -eval (Tape s) = return $ Tape s -eval (Bool b) = return $ Bool b -eval (List []) = return Nil -eval Nil = return Nil +eval (Numb i) = return $ Numb i +eval (Tape s) = return $ Tape s +eval (Bool b) = return $ Bool b +eval (List []) = return Nil +eval Nil = return Nil eval n@(Atom _) = getVar n - -eval (List [Atom "showSF", rest]) = return . Tape . T.pack $ show rest +eval (List [Atom "showSF", rest]) = return . Tape . T.pack $ show rest eval (List ((:) (Atom "showSF") rest)) = return . Tape . T.pack . show $ List rest - eval (List [Atom "quote", val]) = return val - eval (List [Atom "if", pred_, then_, else_]) = do ifRes <- eval pred_ case ifRes of - (Bool True) -> eval then_ + (Bool True) -> eval then_ (Bool False) -> eval else_ _ -> throw $ BadSpecialForm "if's first arg must eval into a boolean" -eval (List ( (:) (Atom "if") _)) = +eval (List ((:) (Atom "if") _)) = throw $ BadSpecialForm "(if )" - eval (List [Atom "begin", rest]) = evalBody rest -eval (List ((:) (Atom "begin") rest )) = evalBody $ List rest - +eval (List ((:) (Atom "begin") rest)) = evalBody $ List rest -- top-level define -- TODO: how to make this eval correctly? -eval (List [Atom "define", List (name:args), body]) = do - Env{..} <- ask +eval (List [Atom "define", List (name : args), body]) = do + Env {..} <- ask _ <- eval body - bindArgsEval (name:args) [body] name - + bindArgsEval (name : args) [body] name eval (List [Atom "define", name, body]) = do - Env{..} <- ask + Env {..} <- ask _ <- eval body bindArgsEval [name] [body] name - eval (List [Atom "let", List pairs, expr]) = do - Env{..} <- ask + Env {..} <- ask atoms <- mapM ensureAtom $ getEven pairs - vals <- mapM eval $ getOdd pairs + vals <- mapM eval $ getOdd pairs bindArgsEval atoms vals expr - -eval (List (Atom "let":_) ) = +eval (List (Atom "let" : _)) = throw $ BadSpecialForm "let function expects list of parameters and S-Expression body\n(let )" - - eval (List [Atom "lambda", List params, expr]) = do ctx <- ask - return $ Func (IFunc $ applyFunc expr params) ctx -eval (List (Atom "lambda":_) ) = throw $ BadSpecialForm "lambda function expects list of parameters and S-Expression body\n(lambda )" - - + return $ Func (IFunc $ applyFunc expr params) ctx +eval (List (Atom "lambda" : _)) = throw $ BadSpecialForm "lambda function expects list of parameters and S-Expression body\n(lambda )" -- needed to get cadr, etc to work -eval (List [Atom "cdr", List [Atom "quote", List (_:xs)]]) = +eval (List [Atom "cdr", List [Atom "quote", List (_ : xs)]]) = return $ List xs -eval (List [Atom "cdr", arg@(List (x:xs))]) = +eval (List [Atom "cdr", arg@(List (x : xs))]) = case x of - -- proxy for if the list can be evaluated - Atom _ -> do - val <- eval arg - eval $ List [Atom "cdr", val] - _ -> return $ List xs - - -eval (List [Atom "car", List [Atom "quote", List (x:_)]]) = - return $ x -eval (List [Atom "car", arg@(List (x:_))]) = + -- proxy for if the list can be evaluated + Atom _ -> do + val <- eval arg + eval $ List [Atom "cdr", val] + _ -> return $ List xs +eval (List [Atom "car", List [Atom "quote", List (x : _)]]) = + return $ x +eval (List [Atom "car", arg@(List (x : _))]) = case x of - Atom _ -> do - val <- eval arg - eval $ List [Atom "car", val] - _ -> return $ x - - + Atom _ -> do + val <- eval arg + eval $ List [Atom "car", val] + _ -> return $ x eval (List ((:) x xs)) = do - Env{..} <- ask + Env {..} <- ask funVar <- eval x xVal <- mapM eval xs case funVar of - (IFun (IFunc internalFn)) -> - internalFn xVal - - (Func (IFunc definedFn) (Env benv _)) -> - local (const $ Env benv fenv) $ definedFn xVal - - _ -> - throw $ NotFunction funVar + (IFun (IFunc internalFn)) -> + internalFn xVal + (Func (IFunc definedFn) (Env benv _)) -> + local (const $ Env benv fenv) $ definedFn xVal + _ -> + throw $ NotFunction funVar updateEnv :: T.Text -> Expr -> Env -> Env -updateEnv var e@(IFun _) Env{..} = Env env $ Map.insert var e fenv -updateEnv var e@(Func _ _) Env{..} = Env env $ Map.insert var e fenv -updateEnv var e Env{..} = Env (Map.insert var e env) fenv +updateEnv var e@(IFun _) Env {..} = Env env $ Map.insert var e fenv +updateEnv var e@(Func _ _) Env {..} = Env env $ Map.insert var e fenv +updateEnv var e Env {..} = Env (Map.insert var e env) fenv evalBody :: Expr -> Eval Expr evalBody (List [List ((:) (Atom "define") [Atom var, defExpr]), rest]) = do evalVal <- eval defExpr ctx <- ask local (const $ updateEnv var evalVal ctx) $ eval rest - evalBody (List ((:) (List ((:) (Atom "define") [Atom var, defExpr])) rest)) = do evalVal <- eval defExpr ctx <- ask local (const $ updateEnv var evalVal ctx) $ evalBody $ List rest - evalBody x = eval x diff --git a/Biz/Language/Bs/Expr.hs b/Biz/Language/Bs/Expr.hs index a39c7b6..2452622 100644 --- a/Biz/Language/Bs/Expr.hs +++ b/Biz/Language/Bs/Expr.hs @@ -1,7 +1,8 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE NoImplicitPrelude #-} + module Language.Bs.Expr where import Data.String (String) @@ -13,17 +14,18 @@ import qualified Text.PrettyPrint.Leijen.Text as PP import Text.PrettyPrint.Leijen.Text hiding ((<$>)) type Ctx = Map Text Expr -data Env = Env { env :: Ctx, fenv :: Ctx } - deriving (Eq) -newtype Eval a = Eval { unEval :: ReaderT Env IO a } - deriving (Monad, Functor, Applicative, MonadReader Env, MonadIO) +data Env = Env {env :: Ctx, fenv :: Ctx} + deriving (Eq) + +newtype Eval a = Eval {unEval :: ReaderT Env IO a} + deriving (Monad, Functor, Applicative, MonadReader Env, MonadIO) -data IFunc = IFunc { fn :: [Expr] -> Eval Expr } - deriving (Typeable) +data IFunc = IFunc {fn :: [Expr] -> Eval Expr} + deriving (Typeable) instance Eq IFunc where - (==) _ _ = False + (==) _ _ = False data Expr = Atom Text @@ -37,7 +39,7 @@ data Expr deriving (Typeable, Eq) instance Show Expr where - show = T.unpack . ppexpr + show = T.unpack . ppexpr data LispErrorType = NumArgs Integer [Expr] @@ -55,12 +57,13 @@ data LispErrorType data LispError = LispError Expr LispErrorType instance Show LispErrorType where - show = T.unpack . ppexpr + show = T.unpack . ppexpr instance Show LispError where - show = T.unpack . ppexpr + show = T.unpack . ppexpr instance Exception LispErrorType + instance Exception LispError ppexpr :: Pretty a => a -> Text @@ -70,85 +73,67 @@ ppexpr x = PP.displayTStrict (PP.renderPretty 1.0 70 (pretty x)) --prettyList = encloseSep lparen rparen PP.space instance Pretty Expr where - pretty v = - case v of - Atom a -> - textStrict a - - List ls -> - prettyList $ fmap pretty ls - - Numb n -> - integer n - - Tape t -> - textStrict "\"" <> textStrict t <> textStrict "\"" - - IFun _ -> - textStrict "" - - Func _ _ -> - textStrict "" - - Bool True -> - textStrict "#t" - - Bool False -> - textStrict "#f" - - Nil -> - textStrict "'()" + pretty v = + case v of + Atom a -> + textStrict a + List ls -> + prettyList $ fmap pretty ls + Numb n -> + integer n + Tape t -> + textStrict "\"" <> textStrict t <> textStrict "\"" + IFun _ -> + textStrict "" + Func _ _ -> + textStrict "" + Bool True -> + textStrict "#t" + Bool False -> + textStrict "#f" + Nil -> + textStrict "'()" instance Pretty LispErrorType where pretty err = case err of - NumArgs i args -> - textStrict "number of arguments" - <$$> textStrict "expected" - <+> textStrict (T.pack $ show i) - <$$> textStrict "received" - <+> textStrict (T.pack $ show $ length args) - - - LengthOfList txt i -> - textStrict "length of list in:" - <+> textStrict txt - <$$> textStrict "length:" - <+> textStrict (T.pack $ show i) - - ParseError txt -> - textStrict "cannot parse expr:" - <+> textStrict (T.pack txt) - - TypeMismatch txt expr -> - textStrict "type mismatch:" - <$$> textStrict txt - <$$> pretty expr - - BadSpecialForm txt -> - textStrict "bad special form:" - <$$> textStrict txt - - NotFunction expr -> - textStrict "not a function" - <$$> pretty expr - - UnboundVar txt -> - textStrict "unbound variable:" - <$$> textStrict txt - - Default _ -> - textStrict "default error" - - ReadFileError txt -> - textStrict "error reading file:" - <$$> textStrict txt - - ExpectedList txt -> - textStrict "expected list:" - <$$> textStrict txt + NumArgs i args -> + textStrict "number of arguments" + <$$> textStrict "expected" + <+> textStrict (T.pack $ show i) + <$$> textStrict "received" + <+> textStrict (T.pack $ show $ length args) + LengthOfList txt i -> + textStrict "length of list in:" + <+> textStrict txt + <$$> textStrict "length:" + <+> textStrict (T.pack $ show i) + ParseError txt -> + textStrict "cannot parse expr:" + <+> textStrict (T.pack txt) + TypeMismatch txt expr -> + textStrict "type mismatch:" + <$$> textStrict txt + <$$> pretty expr + BadSpecialForm txt -> + textStrict "bad special form:" + <$$> textStrict txt + NotFunction expr -> + textStrict "not a function" + <$$> pretty expr + UnboundVar txt -> + textStrict "unbound variable:" + <$$> textStrict txt + Default _ -> + textStrict "default error" + ReadFileError txt -> + textStrict "error reading file:" + <$$> textStrict txt + ExpectedList txt -> + textStrict "expected list:" + <$$> textStrict txt instance Pretty LispError where pretty (LispError expr typ) = - textStrict "error evaluating:" + textStrict "error evaluating:" <$$> indent 4 (pretty expr) <$$> pretty typ diff --git a/Biz/Language/Bs/Parser.hs b/Biz/Language/Bs/Parser.hs index 3044a60..574536d 100644 --- a/Biz/Language/Bs/Parser.hs +++ b/Biz/Language/Bs/Parser.hs @@ -1,10 +1,12 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} -module Language.Bs.Parser ( - readExpr -, readExprFile -) where + +module Language.Bs.Parser + ( readExpr, + readExprFile, + ) +where import Control.Monad (fail) import Control.Monad (mzero) @@ -23,15 +25,16 @@ lexer :: Tok.GenTokenParser T.Text () Identity lexer = Tok.makeTokenParser style style :: Tok.GenLanguageDef T.Text () Identity -style = Lang.emptyDef { - Tok.commentStart = "#|" - , Tok.commentEnd = "|#" - , Tok.commentLine = ";" - , Tok.opStart = mzero - , Tok.opLetter = mzero - , Tok.identStart = letter <|> oneOf "!$%&*/:<=>?^_~" - , Tok.identLetter = digit <|> letter <|> oneOf "!$%&*/:<=>?^_~+-.@" - } +style = + Lang.emptyDef + { Tok.commentStart = "#|", + Tok.commentEnd = "|#", + Tok.commentLine = ";", + Tok.opStart = mzero, + Tok.opLetter = mzero, + Tok.identStart = letter <|> oneOf "!$%&*/:<=>?^_~", + Tok.identLetter = digit <|> letter <|> oneOf "!$%&*/:<=>?^_~+-.@" + } parens :: Parser a -> Parser a parens = Tok.parens lexer @@ -48,9 +51,10 @@ quoted p = try (char '\'') *> p identifier :: Parser T.Text identifier = T.pack <$> (Tok.identifier lexer <|> specialIdentifier) "identifier" where - specialIdentifier :: Parser String - specialIdentifier = lexeme $ try $ - string "-" <|> string "+" <|> string "..." + specialIdentifier :: Parser String + specialIdentifier = + lexeme $ try $ + string "-" <|> string "+" <|> string "..." -- | The @Radix@ type consists of a base integer (e.g. @10@) and a parser for -- digits in that base (e.g. @digit@). @@ -61,7 +65,7 @@ type Radix = (Integer, Parser Char) numberWithRadix :: Radix -> Parser Integer numberWithRadix (base, baseDigit) = do digits <- many1 baseDigit - let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits + let n = foldl (\x d -> base * x + toInteger (digitToInt d)) 0 digits seq n (return n) decimal :: Parser Integer @@ -70,9 +74,10 @@ decimal = Tok.decimal lexer -- | Parse a sign, return either @id@ or @negate@ based on the sign parsed. -- Copied from Text.Parsec.Token sign :: Parser (Integer -> Integer) -sign = char '-' *> return negate - <|> char '+' *> return identity - <|> return identity +sign = + char '-' *> return negate + <|> char '+' *> return identity + <|> return identity intRadix :: Radix -> Parser Integer intRadix r = sign <*> numberWithRadix r @@ -84,26 +89,29 @@ nil :: Parser () nil = try ((char '\'') *> string "()") *> return () "nil" hashVal :: Parser Expr -hashVal = lexeme $ char '#' - *> (char 't' *> return (Bool True) - <|> char 'f' *> return (Bool False) - <|> char 'b' *> (Numb <$> intRadix (2, oneOf "01")) - <|> char 'o' *> (Numb <$> intRadix (8, octDigit)) - <|> char 'd' *> (Numb <$> intRadix (10, digit)) - <|> char 'x' *> (Numb <$> intRadix (16, hexDigit)) - <|> oneOf "ei" *> fail "Unsupported: exactness" - <|> char '(' *> fail "Unsupported: vector" - <|> char '\\' *> fail "Unsupported: char") - +hashVal = + lexeme $ + char '#' + *> ( char 't' *> return (Bool True) + <|> char 'f' *> return (Bool False) + <|> char 'b' *> (Numb <$> intRadix (2, oneOf "01")) + <|> char 'o' *> (Numb <$> intRadix (8, octDigit)) + <|> char 'd' *> (Numb <$> intRadix (10, digit)) + <|> char 'x' *> (Numb <$> intRadix (16, hexDigit)) + <|> oneOf "ei" *> fail "Unsupported: exactness" + <|> char '(' *> fail "Unsupported: vector" + <|> char '\\' *> fail "Unsupported: char" + ) lispVal :: Parser Expr -lispVal = hashVal - <|> Nil <$ nil - <|> Numb <$> try (sign <*> decimal) - <|> Atom <$> identifier - <|> Tape <$> textLiteral - <|> _Quote <$> quoted lispVal - <|> List <$> parens manyExpr +lispVal = + hashVal + <|> Nil <$ nil + <|> Numb <$> try (sign <*> decimal) + <|> Atom <$> identifier + <|> Tape <$> textLiteral + <|> _Quote <$> quoted lispVal + <|> List <$> parens manyExpr manyExpr :: Parser [Expr] manyExpr = lispVal `sepBy` whitespace diff --git a/Biz/Language/Bs/Primitives.hs b/Biz/Language/Bs/Primitives.hs index c074c59..4c70499 100644 --- a/Biz/Language/Bs/Primitives.hs +++ b/Biz/Language/Bs/Primitives.hs @@ -1,5 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} + -- | bs primitives -- -- I would like to reduce the number of primitives in the language to some @@ -18,134 +19,138 @@ import Protolude import System.Directory import System.IO -type Prim = [(T.Text, Expr)] -type Unary = Expr -> Eval Expr +type Prim = [(T.Text, Expr)] + +type Unary = Expr -> Eval Expr + type Binary = Expr -> Expr -> Eval Expr mkF :: ([Expr] -> Eval Expr) -> Expr mkF = IFun . IFunc primEnv :: Prim -primEnv = [ - ("+" , mkF $ binopFold (numOp (+)) (Numb 0) ) - , ("*" , mkF $ binopFold (numOp (*)) (Numb 1) ) - , ("string-append", mkF $ binopFold (strOp (<>)) (Tape "") ) - , ("-" , mkF $ binop $ numOp (-)) - , ("<" , mkF $ binop $ numCmp (<)) - , ("<=" , mkF $ binop $ numCmp (<=)) - , (">" , mkF $ binop $ numCmp (>)) - , (">=" , mkF $ binop $ numCmp (>=)) - , ("==" , mkF $ binop $ numCmp (==)) - , ("even?" , mkF $ unop $ numBool even) - , ("odd?" , mkF $ unop $ numBool odd) - , ("neg?" , mkF $ unop $ numBool (< 0)) - , ("pos?" , mkF $ unop $ numBool (> 0)) - , ("eq?" , mkF $ binop eqCmd ) - , ("null?" , mkF $ unop (eqCmd Nil) ) - , ("bl-eq?" , mkF $ binop $ eqOp (==)) - , ("and" , mkF $ binopFold (eqOp (&&)) (Bool True)) - , ("or" , mkF $ binopFold (eqOp (||)) (Bool False)) - , ("not" , mkF $ unop $ notOp) - , ("cons" , mkF $ Language.Bs.Primitives.cons) - , ("cdr" , mkF $ Language.Bs.Primitives.cdr) - , ("car" , mkF $ Language.Bs.Primitives.car) - , ("quote" , mkF $ quote) - , ("file?" , mkF $ unop fileExists) - , ("slurp" , mkF $ unop slurp) - , ("wslurp" , mkF $ unop wSlurp) - , ("put" , mkF $ binop put_) +primEnv = + [ ("+", mkF $ binopFold (numOp (+)) (Numb 0)), + ("*", mkF $ binopFold (numOp (*)) (Numb 1)), + ("string-append", mkF $ binopFold (strOp (<>)) (Tape "")), + ("-", mkF $ binop $ numOp (-)), + ("<", mkF $ binop $ numCmp (<)), + ("<=", mkF $ binop $ numCmp (<=)), + (">", mkF $ binop $ numCmp (>)), + (">=", mkF $ binop $ numCmp (>=)), + ("==", mkF $ binop $ numCmp (==)), + ("even?", mkF $ unop $ numBool even), + ("odd?", mkF $ unop $ numBool odd), + ("neg?", mkF $ unop $ numBool (< 0)), + ("pos?", mkF $ unop $ numBool (> 0)), + ("eq?", mkF $ binop eqCmd), + ("null?", mkF $ unop (eqCmd Nil)), + ("bl-eq?", mkF $ binop $ eqOp (==)), + ("and", mkF $ binopFold (eqOp (&&)) (Bool True)), + ("or", mkF $ binopFold (eqOp (||)) (Bool False)), + ("not", mkF $ unop $ notOp), + ("cons", mkF $ Language.Bs.Primitives.cons), + ("cdr", mkF $ Language.Bs.Primitives.cdr), + ("car", mkF $ Language.Bs.Primitives.car), + ("quote", mkF $ quote), + ("file?", mkF $ unop fileExists), + ("slurp", mkF $ unop slurp), + ("wslurp", mkF $ unop wSlurp), + ("put", mkF $ binop put_) ] unop :: Unary -> [Expr] -> Eval Expr -unop op [x] = op x -unop _ args = throw $ NumArgs 1 args +unop op [x] = op x +unop _ args = throw $ NumArgs 1 args binop :: Binary -> [Expr] -> Eval Expr -binop op [x,y] = op x y -binop _ args = throw $ NumArgs 2 args +binop op [x, y] = op x y +binop _ args = throw $ NumArgs 2 args -fileExists :: Expr -> Eval Expr +fileExists :: Expr -> Eval Expr fileExists (Tape txt) = Bool <$> liftIO (doesFileExist $ T.unpack txt) -fileExists val = throw $ TypeMismatch "read expects string, instead got: " val +fileExists val = throw $ TypeMismatch "read expects string, instead got: " val -slurp :: Expr -> Eval Expr +slurp :: Expr -> Eval Expr slurp (Tape txt) = liftIO $ wFileSlurp txt -slurp val = throw $ TypeMismatch "read expects string, instead got: " val +slurp val = throw $ TypeMismatch "read expects string, instead got: " val wFileSlurp :: T.Text -> IO Expr wFileSlurp fileName = withFile (T.unpack fileName) ReadMode go - where go = readTextFile fileName + where + go = readTextFile fileName openURL :: T.Text -> IO Expr openURL x = do - req <- simpleHTTP (getRequest $ T.unpack x) + req <- simpleHTTP (getRequest $ T.unpack x) body <- getResponseBody req return $ Tape $ T.pack body wSlurp :: Expr -> Eval Expr -wSlurp (Tape txt) = liftIO $ openURL txt +wSlurp (Tape txt) = liftIO $ openURL txt wSlurp val = throw $ TypeMismatch "wSlurp expects a string, instead got: " val readTextFile :: T.Text -> Handle -> IO Expr readTextFile fileName h = do exists <- doesFileExist $ T.unpack fileName if exists - then (TIO.hGetContents h) >>= (return . Tape) - else throw $ ReadFileError $ T.concat [" file does not exist: ", fileName] + then (TIO.hGetContents h) >>= (return . Tape) + else throw $ ReadFileError $ T.concat [" file does not exist: ", fileName] put_ :: Expr -> Expr -> Eval Expr -put_ (Tape file) (Tape msg) = liftIO $ wFilePut file msg -put_ (Tape _) val = throw $ TypeMismatch "put expects string in the second argument (try using show), instead got: " val -put_ val _ = throw $ TypeMismatch "put expects string, instead got: " val +put_ (Tape file) (Tape msg) = liftIO $ wFilePut file msg +put_ (Tape _) val = throw $ TypeMismatch "put expects string in the second argument (try using show), instead got: " val +put_ val _ = throw $ TypeMismatch "put expects string, instead got: " val wFilePut :: T.Text -> T.Text -> IO Expr wFilePut fileName msg = withFile (T.unpack fileName) WriteMode go - where go = putTextFile fileName msg + where + go = putTextFile fileName msg putTextFile :: T.Text -> T.Text -> Handle -> IO Expr putTextFile fileName msg h = do canWrite <- hIsWritable h if canWrite - then (TIO.hPutStr h msg) >> (return $ Tape msg) - else throw $ ReadFileError $ T.concat [" file does not exist: ", fileName] + then (TIO.hPutStr h msg) >> (return $ Tape msg) + else throw $ ReadFileError $ T.concat [" file does not exist: ", fileName] binopFold :: Binary -> Expr -> [Expr] -> Eval Expr binopFold op farg args = case args of - []-> throw $ NumArgs 2 args - [a,b] -> op a b - _ -> foldM op farg args + [] -> throw $ NumArgs 2 args + [a, b] -> op a b + _ -> foldM op farg args numBool :: (Integer -> Bool) -> Expr -> Eval Expr numBool op (Numb x) = return $ Bool $ op x -numBool _ x = throw $ TypeMismatch "numeric op " x +numBool _ x = throw $ TypeMismatch "numeric op " x numOp :: (Integer -> Integer -> Integer) -> Expr -> Expr -> Eval Expr -numOp op (Numb x) (Numb y) = return $ Numb $ op x y -numOp _ Nil (Numb y) = return $ Numb y -numOp _ (Numb x) Nil = return $ Numb x -numOp _ x (Numb _) = throw $ TypeMismatch "numeric op" x -numOp _ (Numb _) y = throw $ TypeMismatch "numeric op" y -numOp _ x _ = throw $ TypeMismatch "numeric op" x +numOp op (Numb x) (Numb y) = return $ Numb $ op x y +numOp _ Nil (Numb y) = return $ Numb y +numOp _ (Numb x) Nil = return $ Numb x +numOp _ x (Numb _) = throw $ TypeMismatch "numeric op" x +numOp _ (Numb _) y = throw $ TypeMismatch "numeric op" y +numOp _ x _ = throw $ TypeMismatch "numeric op" x strOp :: (T.Text -> T.Text -> T.Text) -> Expr -> Expr -> Eval Expr strOp op (Tape x) (Tape y) = return $ Tape $ op x y -strOp _ Nil (Tape y) = return $ Tape y -strOp _ (Tape x) Nil = return $ Tape x -strOp _ x (Tape _) = throw $ TypeMismatch "string op" x -strOp _ (Tape _) y = throw $ TypeMismatch "string op" y -strOp _ x _ = throw $ TypeMismatch "string op" x +strOp _ Nil (Tape y) = return $ Tape y +strOp _ (Tape x) Nil = return $ Tape x +strOp _ x (Tape _) = throw $ TypeMismatch "string op" x +strOp _ (Tape _) y = throw $ TypeMismatch "string op" y +strOp _ x _ = throw $ TypeMismatch "string op" x eqOp :: (Bool -> Bool -> Bool) -> Expr -> Expr -> Eval Expr eqOp op (Bool x) (Bool y) = return $ Bool $ op x y -eqOp _ x (Bool _) = throw $ TypeMismatch "bool op" x -eqOp _ (Bool _) y = throw $ TypeMismatch "bool op" y -eqOp _ x _ = throw $ TypeMismatch "bool op" x +eqOp _ x (Bool _) = throw $ TypeMismatch "bool op" x +eqOp _ (Bool _) y = throw $ TypeMismatch "bool op" y +eqOp _ x _ = throw $ TypeMismatch "bool op" x numCmp :: (Integer -> Integer -> Bool) -> Expr -> Expr -> Eval Expr -numCmp op (Numb x) (Numb y) = return . Bool $ op x y -numCmp _ x (Numb _) = throw $ TypeMismatch "numeric op" x -numCmp _ (Numb _) y = throw $ TypeMismatch "numeric op" y -numCmp _ x _ = throw $ TypeMismatch "numeric op" x +numCmp op (Numb x) (Numb y) = return . Bool $ op x y +numCmp _ x (Numb _) = throw $ TypeMismatch "numeric op" x +numCmp _ (Numb _) y = throw $ TypeMismatch "numeric op" y +numCmp _ x _ = throw $ TypeMismatch "numeric op" x notOp :: Expr -> Eval Expr notOp (Bool True) = return $ Bool False @@ -157,27 +162,27 @@ eqCmd (Atom x) (Atom y) = return . Bool $ x == y eqCmd (Numb x) (Numb y) = return . Bool $ x == y eqCmd (Tape x) (Tape y) = return . Bool $ x == y eqCmd (Bool x) (Bool y) = return . Bool $ x == y -eqCmd Nil Nil = return $ Bool True -eqCmd _ _ = return $ Bool False +eqCmd Nil Nil = return $ Bool True +eqCmd _ _ = return $ Bool False cons :: [Expr] -> Eval Expr -cons [x,(List ys)] = return $ List $ x:ys -cons [x,y] = return $ List [x,y] -cons _ = throw $ ExpectedList "cons, in second argument" +cons [x, (List ys)] = return $ List $ x : ys +cons [x, y] = return $ List [x, y] +cons _ = throw $ ExpectedList "cons, in second argument" car :: [Expr] -> Eval Expr -car [List [] ] = return Nil -car [List (x:_)] = return x -car [] = return Nil -car _ = throw $ ExpectedList "car" +car [List []] = return Nil +car [List (x : _)] = return x +car [] = return Nil +car _ = throw $ ExpectedList "car" cdr :: [Expr] -> Eval Expr -cdr [List (_:xs)] = return $ List xs -cdr [List []] = return Nil -cdr [] = return Nil -cdr _ = throw $ ExpectedList "cdr" +cdr [List (_ : xs)] = return $ List xs +cdr [List []] = return Nil +cdr [] = return Nil +cdr _ = throw $ ExpectedList "cdr" quote :: [Expr] -> Eval Expr -quote [List xs] = return $ List $ Atom "quote" : xs -quote [expr] = return $ List $ Atom "quote" : [expr] -quote args = throw $ NumArgs 1 args +quote [List xs] = return $ List $ Atom "quote" : xs +quote [expr] = return $ List $ Atom "quote" : [expr] +quote args = throw $ NumArgs 1 args diff --git a/Biz/Language/Bs/Repl.hs b/Biz/Language/Bs/Repl.hs index 64ffaa2..24f1bcd 100644 --- a/Biz/Language/Bs/Repl.hs +++ b/Biz/Language/Bs/Repl.hs @@ -1,8 +1,10 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoImplicitPrelude #-} -module Language.Bs.Repl ( -mainLoop -) where + +module Language.Bs.Repl + ( mainLoop, + ) +where import Control.Monad.Trans import Data.String @@ -22,7 +24,8 @@ repl = do case minput of Nothing -> outputStrLn "bye." Just input -> (liftIO $ process input) >> repl - --Just input -> (liftIO $ processToAST input) >> repl + +--Just input -> (liftIO $ processToAST input) >> repl process :: String -> IO () process str = do -- cgit v1.2.3