Repository: l29ah/muesli Branch: master Commit: 344e8f02733b Files: 12 Total size: 32.9 KB Directory structure: gitextract_lq3jvk9y/ ├── .gitignore ├── Database.hs ├── DatabaseTools.hs ├── LICENSE ├── Main.hs ├── Muesli.hs ├── README.md ├── Setup.lhs ├── Types.hs ├── mktable.hs ├── mktable.sh └── muesli.cabal ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.swp *.hi *.o muesli ================================================ FILE: Database.hs ================================================ {-# OPTIONS_GHC -fno-warn-tabs #-} module Database where import qualified Data.Vector.Fixed as F import DatabaseTools import Types -- nuts:prote, fat, carbs, fiber, -- elem:potass, sodium, calciu, magnes, phosph, iron, iodine, zinc, seleni, copper, chromi, mangane,molybde,chlorid,fluoride, -- vita:a, c, d, e, k, thiami, ribofl, niacin, pantot, b6, biotin, folate, b12, choline,omega3, omega6, -- e aa:His, Ile, Leu, Lys, Met, Phe, Thr, Trp, Val, -- o aa:Ala, Arg, Asn, Asp, Cys, Glu, Gln, Gly, Orn, Pro, Sel, Ser, Tyr -- e fa:ALA, EPA, DPA, DHA, LA, GLA, AA -- ↘per 100g raisins = Source "raisin" $ Substance 100 $ usda $ mkL 3 0.5 79 5 -- USDA 09299 + http://www.whfoods.com/genpage.php?tname=nutrientprofile&dbid=24 + 09298 0.773 0.017 0.044 0.032 0.097 2.1e-3 idk 240e-6 0.63e-6 328e-6 idk 0.29e-3 idk idk 220e-6 0 3.6e-3 0 120e-6 3.5e-6 75e-6 166e-6 1e-3 93e-6 228e-6 2e-6 3.7e-6 0 11.1e-3 0 1e-3 7.20e-2 5.70e-2 9.60e-2 8.40e-2 7.70e-2 6.50e-2 7.70e-2 5.00e-2 8.30e-2 1.05e-1 4.13e-1 idk 1.10e-1 1.90e-2 1.64e-1 idk 8.00e-2 idk 2.54e-1 idk 7.00e-2 1.20e-2 idk 0.000e0 0.000e0 0.000e0 idk idk idk undevit = Source "undevit" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1e-3 75e-3 0 10e-3 0 2e-3 2e-3 20e-3 3e-3 3e-3 0 70e-6 2e-6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 undevitmar = Source "undevit" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 435e-6 60e-3 0 10e-3 0 1.4e-3 1.6e-3 18e-3 6.5e-3 2e-3 0 200e-6 1e-6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 gendevit = Source "gendevit" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1e-3 75e-3 6.25e-6 5e-3 0 1.5e-3 1.5e-3 10e-3 3e-3 2e-3 0 300e-6 10e-6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 sunflowerOil = Source "sunfloweroil" $ Substance 100 $ usda $ mkL -- USDA 04506, manually corrected assuming 18:2 is LA 0.00e0 100.00e0 0.00e0 0.0e0 0e-3 0e-3 0e-3 0e-3 0e-3 0.00e-3 idk 0.00e-3 0.0e-6 0.000e-3 idk idk idk idk idk 0e-6 0.0e-3 0.0e-6 41.08e-3 5.4e-6 0.000e-3 0.000e-3 0.000e-3 0.000e-3 0.000e-3 idk 0e-6 0.00e-6 0.2e-3 0.0 65.7 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 0.000e0 idk 0.000e0 0.000e0 0.000e0 idk 0.000e0 idk 0.000e0 idk 0.000e0 0.000e0 idk 0.000e0 0.000e0 0.000e0 65.7 idk idk brazilNuts = Source "brazilnuts" $ Substance 100 $ usda $ mkL -- USDA 12078 14.32e0 67.10e0 11.74e0 7.5e0 659e-3 3e-3 160e-3 376e-3 725e-3 2.43e-3 idk 4.06e-3 1917.0e-6 1.743e-3 idk 1.223e-3 idk idk idk 0e-6 0.7e-3 0.0e-6 5.65e-3 0.0e-6 0.617e-3 0.035e-3 0.295e-3 0.184e-3 0.101e-3 idk 22e-6 0.00e-6 28.8e-3 1.8e-2 23.877000000000002 0.409e0 0.518e0 1.190e0 0.490e0 0.365e0 0.639e0 0.365e0 0.135e0 0.760e0 0.609e0 2.140e0 idk 1.325e0 0.306e0 3.190e0 idk 0.733e0 idk 0.706e0 idk 0.676e0 0.416e0 0.018e0 0.000e0 0.000e0 0.000e0 23.859e0 0.018e0 idk oat = Source "oat" $ Substance 100 $ usda $ mkL -- USDA 08120 + http://www.whfoods.com/genpage.php?tname=nutrientprofile&dbid=109 13.15e0 6.52e0 67.70e0 10.1e0 362e-3 6e-3 52e-3 138e-3 410e-3 4.25e-3 idk 3.64e-3 28.9e-6 0.391e-3 idk 3.630e-3 idk idk idk 0e-6 0.0e-3 0.0e-6 0.42e-3 2.0e-6 0.460e-3 0.155e-3 1.125e-3 1.120e-3 0.100e-3 idk 32e-6 0.00e-6 40.4e-3 0.0 0.0 0.405e0 0.694e0 1.284e0 0.701e0 0.575e0 0.895e0 0.575e0 0.234e0 0.937e0 0.881e0 1.192e0 idk 1.448e0 0.408e0 3.712e0 idk 0.841e0 idk 0.934e0 idk 0.750e0 0.573e0 idk idk idk idk idk idk idk buckwheat = Source "buckwheat" $ Substance 100 $ usda $ mkL -- USDA 20008 13.25e0 3.40e0 71.50e0 10.0e0 460e-3 1e-3 18e-3 231e-3 347e-3 2.20e-3 idk 2.40e-3 8.3e-6 1.100e-3 idk 1.300e-3 idk idk idk 0e-6 0.0e-3 0.0e-6 idk idk 0.101e-3 0.425e-3 7.020e-3 1.233e-3 0.210e-3 idk 30e-6 0.00e-6 idk idk idk 0.309e0 0.498e0 0.832e0 0.672e0 0.506e0 0.520e0 0.506e0 0.192e0 0.678e0 0.748e0 0.982e0 idk 1.133e0 0.229e0 2.046e0 idk 1.031e0 idk 0.507e0 idk 0.685e0 0.241e0 idk 0.000e0 0.000e0 0.000e0 idk idk idk buckwheatFlakes = Source "buckwheatflakes" $ Substance 100 $ usda $ mkL -- same as buckwheat 13.25e0 3.40e0 71.50e0 10.0e0 460e-3 1e-3 18e-3 231e-3 347e-3 2.20e-3 idk 2.40e-3 8.3e-6 1.100e-3 idk 1.300e-3 idk idk idk 0e-6 0.0e-3 0.0e-6 idk idk 0.101e-3 0.425e-3 7.020e-3 1.233e-3 0.210e-3 idk 30e-6 0.00e-6 idk idk idk 0.309e0 0.498e0 0.832e0 0.672e0 0.506e0 0.520e0 0.506e0 0.192e0 0.678e0 0.748e0 0.982e0 idk 1.133e0 0.229e0 2.046e0 idk 1.031e0 idk 0.507e0 idk 0.685e0 0.241e0 idk 0.000e0 0.000e0 0.000e0 idk idk idk parsley = Source "parsley" $ Substance 100 $ usda $ mkL -- USDA 11297 2.97e0 7.90e-1 6.33e0 3.30e0 5.54e-1 5.60e-2 1.38e-1 5.00e-2 5.80e-2 6.20e-3 idk 1.07e-3 1.00e-7 1.49e-4 idk 1.60e-4 idk idk idk 4.21e-4 idk 0.00e0 7.50e-4 1.64e-3 8.60e-5 9.80e-5 1.31e-3 4.00e-4 9.00e-5 idk 1.52e-4 0.00e0 12.8e-3 8e-3 118e-3 -- http://nutritiondata.self.com/facts/vegetables-and-vegetable-products/2513/2 6.10e-2 1.18e-1 2.04e-1 1.81e-1 1.22e-1 1.45e-1 1.22e-1 4.50e-2 1.72e-1 1.95e-1 1.22e-1 idk 2.94e-1 1.40e-2 2.49e-1 idk 1.45e-1 idk 2.13e-1 idk 1.36e-1 8.20e-2 idk 0.000e0 0.000e0 0.000e0 idk idk idk parsleyDried = Source "parsleydried" $ Substance 100 $ usda $ mkL -- USDA 02029 26.63e0 5.48e0 50.64e0 26.7e0 2683e-3 452e-3 1140e-3 400e-3 436e-3 22.04e-3 idk 5.44e-3 14.1e-6 0.780e-3 idk 9.810e-3 idk idk idk 97e-6 125.0e-3 0.0e-6 8.96e-3 1359.5e-6 0.196e-3 2.383e-3 9.943e-3 1.062e-3 0.900e-3 idk 180e-6 0.00e-6 97.1e-3 1.86 1.264 0.718e0 1.546e0 2.794e0 2.098e0 1.193e0 1.712e0 1.193e0 0.475e0 2.021e0 1.778e0 1.756e0 idk 3.169e0 0.298e0 3.688e0 idk 1.756e0 idk 2.010e0 idk 1.159e0 1.159e0 1.860e0 0.000e0 0.000e0 0.000e0 1.248e0 0.016e0 idk flaxseedOil = Source "flaxseedoil" $ Substance 100 $ usda $ mkL -- USDA 42231 0.11e0 99.98e0 0.00e0 0.0e0 0e-3 0e-3 1e-3 0e-3 1e-3 0.00e-3 idk 0.07e-3 0.0e-6 0.000e-3 idk 0.000e-3 idk idk idk 0e-6 0.0e-3 0.0e-6 0.47e-3 9.3e-6 0.000e-3 0.000e-3 0.000e-3 idk 0.000e-3 idk 0e-6 0.00e-6 0.2e-3 53.368 14.246 idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk 53.368e0 0.000e0 0.000e0 0.000e0 14.246e0 0.000e0 idk fishOilCodLiver = Source "codliveroil" $ Substance 100 $ usda $ mkL -- USDA 04589 0.00e0 100.00e0 0.00e0 0.0e0 0e-3 0e-3 0e-3 0e-3 0e-3 0.00e-3 idk 0.00e-3 0.0e-6 0.000e-3 idk 0.000e-3 idk idk idk 30000e-6 0.0e-3 250.0e-6 idk idk idk 0.000e-3 0.000e-3 0.000e-3 0.000e-3 idk 0e-6 0.00e-6 idk 18.801000000000002 0.0 idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk idk 6.898e0 0.935e0 10.968e0 idk idk idk eggHardboiled = Source "egghardboiled" $ Substance 100 $ usda $ mkL -- USDA 01129 12.58e0 10.61e0 1.12e0 0.0e0 126e-3 124e-3 50e-3 10e-3 172e-3 1.19e-3 idk 1.05e-3 30.8e-6 0.013e-3 idk 0.026e-3 idk idk 4.8e-6 149e-6 0.0e-3 2.2e-6 1.03e-3 0.3e-6 0.066e-3 0.513e-3 0.064e-3 1.398e-3 0.121e-3 idk 44e-6 1.11e-6 293.8e-3 4.3e-2 0.0 0.298e0 0.686e0 1.075e0 0.904e0 0.604e0 0.668e0 0.604e0 0.153e0 0.767e0 0.700e0 0.755e0 idk 1.264e0 0.292e0 1.644e0 idk 0.423e0 idk 0.501e0 idk 0.936e0 0.513e0 idk 0.005e0 0.000e0 0.038e0 idk idk idk soyflourdefatted = Source "soyflourdefatted" $ Substance 100 $ usda $ mkL -- USDA 16117 51.46e0 1.22e0 33.92e0 17.5e0 2384e-3 20e-3 241e-3 290e-3 674e-3 9.24e-3 idk 2.46e-3 1.7e-6 4.065e-3 idk 3.018e-3 idk idk idk 2e-6 0.0e-3 0.0e-6 0.12e-3 4.1e-6 0.698e-3 0.253e-3 2.612e-3 1.995e-3 0.574e-3 idk 305e-6 0.00e-6 11.3e-3 0.0 0.0 1.268e0 2.281e0 3.828e0 3.129e0 2.042e0 2.453e0 2.042e0 0.683e0 2.346e0 2.215e0 3.647e0 idk 5.911e0 0.757e0 9.106e0 idk 2.174e0 idk 2.750e0 idk 2.725e0 1.778e0 idk 0.000e0 0.000e0 0.000e0 idk idk idk naCl = Source "nacl" $ Substance 100 $ mkL 0 0 0 0 0 39.32 0 0 0 0 0 0 0 0 0 0 0 60.68 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 naClI = Source "nacl" $ Substance 100 $ mkL 0 0 0 0 0 39.32 0 0 0 0 2.5e-3 0 0 0 0 0 0 60.68 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 kCl = Source "kcl" $ Substance 100 $ mkL 0 0 0 0 52.41 0 0 0 0 0 0 0 0 0 0 0 0 47.6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 kCitrateH2O = Source "kcitrate" $ Substance 100 $ mkL -- K3C6H7O8 0 0 0 0 36.111 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 kSelenate = Source "kselenate" $ Substance 100 $ mkL -- K2SeO4 0 0 0 0 35.294 0 0 0 0 0 0 0 35.747 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 caCl = Source "cacl" $ Substance 100 $ mkL 0 0 0 0 0 0 36.1 0 0 0 0 0 0 0 0 0 0 63.9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 caCl2x2H2O = Source "cacl2x2h2o" $ Substance 100 $ mkL 0 0 0 0 0 0 27.21 0 0 0 0 0 0 0 0 0 0 48.3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ca2CO3 = Source "chalk" $ Substance 100 $ mkL 0 0 0 0 0 0 57.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 naI = Source "nai" $ Substance 1 $ mkL 0 0 0 0 0 0.1534 0 0 0 0 0.8466 0 0 0 0 0 0 60.68 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ascorbicAcid = Source "ascorbica" $ Substance 100 $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 d3 = Source "d3" $ Substance 100 $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 vigantol = Source "vigantol" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12.5e-6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 nowD35000 = Source "nowd3-5000" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 125e-6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 cholineBitartrate = Source "cholinebitartrate" $ Substance 100 $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41.1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 snK = Source "sourcenaturalsk" $ Pill $ mkL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5e-3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ================================================ FILE: DatabaseTools.hs ================================================ {-# LANGUAGE DataKinds, FlexibleContexts, TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-tabs #-} module DatabaseTools where import Data.Proxy import qualified Data.Vector.Fixed as F import qualified Data.Vector.Fixed.Cont as C import Types mkL = F.mkN (Proxy :: Proxy Nutrients) -- TODO a better value that taints the calculation idk :: Double idk = 0 -- Put 'nan' when the value is unspecified or irrelevant in the target daily uptakes nan = 0/0 -- Put 'todo' when the value is to be fetched todo = idk -- USDA considers fiber a carbohydrate, we don't usda v = F.set (Proxy :: Proxy 2) ((F.index v (Proxy :: Proxy 2)) - (F.index v (Proxy :: Proxy 3))) v ================================================ FILE: LICENSE ================================================ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar 22 rue de Plaisance, 75014 Paris, France Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. ================================================ FILE: Main.hs ================================================ module Main where import qualified Muesli main = Muesli.main ================================================ FILE: Muesli.hs ================================================ #!/usr/bin/env runhaskell {-# LANGUAGE TemplateHaskell, DataKinds, FlexibleContexts #-} {-# OPTIONS_GHC -fno-warn-tabs #-} module Muesli where import Control.Exception import Control.Monad import Data.List import Data.Maybe import Data.Vector.Fixed ((!)) import qualified Data.Vector.Fixed as F import Data.Vector.Fixed.Boxed as V import System.Console.ANSI import System.Console.GetOpt import System.Environment import System.IO import Text.Printf import Database import DatabaseTools import Types fromRecipe :: Recipe -> [(Amount, Source)] fromRecipe (Recipe a b) = a ++ b def :: Nutrients def = F.replicate 0 getNutrients :: Component -> Nutrients getNutrients (Substance _ n) = n getNutrients (Pill n) = n isPill :: Component -> Bool isPill (Pill _) = True isPill _ = False -- target daily energy value -- TODO fix the values hardcoded elsewhere energy :: Kcal energy = 2000 -- Calculate the energetic value cal :: Nutrients -> Kcal cal x = 4 * x!0 + 9 * x!1 + 4 * x!2 amountify :: Component -> Amount -> Component amountify (Pill x) a = Pill $ F.map (* a) x amountify (Substance mass x) a = Substance (mass * a) $ F.map (* a) x sumNutrients :: [(Amount, Source)] -> Nutrients sumNutrients as = foldl (\tsum cnut -> F.zipWith (+) tsum cnut) def $ nutrientify as nutrientify :: [(Amount, Source)] -> [Nutrients] nutrientify as = map (\(amount, (Source _ comp)) -> getNutrients $ amountify comp amount) as energyMultiplier :: Nutrients -> Double energyMultiplier n = energy / (cal n) pills :: Recipe -> [(Amount, Source)] pills r = filter (isPill . sComponent . snd) $ rFoods r substances :: Recipe -> [(Amount, Source)] substances r = filter (not . isPill . sComponent . snd) $ rFoods r normalizeRecipe :: Recipe -> Recipe normalizeRecipe r = let mult = energyMultiplier $ sumNutrients $ substances r in Recipe ((map (\(amount, source) -> (mult * amount, source)) (substances r)) ++ (pills r)) $ rSupplements r -- daily intakes, g at 2Mcal fdardi = mkL 50 78 275 28 4.7 2.3 1.3 0.42 1.25 18e-3 150e-6 11e-3 55e-6 0.9e-3 35e-6 2.3e-3 45e-6 2.3 4e-3 0.9e-3 0.09 20e-6 15e-3 120e-6 1.2e-3 1.3e-3 16e-3 5e-3 1.7e-3 30e-6 0.4e-3 2.4e-6 0.55 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan iomdrirda = mkL nan nan nan nan 4.7 1.5 1 0.4 0.7 15e-3 150e-6 11e-3 55e-6 0.9e-3 35e-6 2.3e-3 45e-6 2.3 4e-3 0.9e-3 0.09 15e-6 15e-3 120e-6 1.2e-3 1.3e-3 16e-3 5e-3 1.3e-3 30e-6 0.4e-3 2.4e-6 0.55 1.6 17 0.91 1.235 2.730 2.470 1.235 2.145 1.3 0.325 1.56 nan nan nan nan 1.235 nan nan nan nan nan nan nan 2.145 nan nan nan nan nan nan nan iomdriul = mkL nan nan nan nan nan 2.3 2.5 0.7 4 45e-3 1.1e-3 40e-3 400e-6 10e-3 nan 11e-3 2e-3 3.6 10e-3 3e-3 2 100e-6 1 nan nan nan 35e-3 nan 100e-3 nan 1e-3 nan 3.5 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan -- calculated for 65kg 18-29yo sedentary male 2450kcal рсн = mkL 59 66 292 16 -- balanced for 2000kcal 2.5 1.3 1 0.4 0.8 10e-3 150e-6 12e-3 70e-6 1e-3 50e-6 2e-3 70e-6 2.3 4e-3 900e-6 90e-3 10e-6 15e-3 120e-6 1.5e-3 1.8e-3 20e-3 5e-3 2e-3 50e-6 400e-6 3e-6 0.5 1.6 7 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan -- nuts:prote, fat, carbs, fiber, -- elem:potass, sodium, calciu, magnes, phosph, iron, iodine, zinc, seleni, copper, chromi, mangane,molybde,chlorid,fluoride, -- vita:a, c, d, e, k, thiami, ribofl, niacin, pantot, b6, biotin, folate, b12, choline,omega3, omega6, -- e aa:His, Ile, Leu, Lys, Met, Phe, Thr, Trp, Val, -- o aa:Ala, Arg, Asn, Asp, Cys, Glu, Gln, Gly, Orn, Pro, Sel, Ser, Tyr -- e fa:ALA, EPA, DPA, DHA, LA, GLA, AA -- the difference against iom rda as seen in https://lpi.oregonstate.edu/publications/rx-health lpi = mkL nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan 0.4 50e-6 nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan nan attenuate :: [(Amount, Source)] -> Double -> [(Amount, Source)] attenuate l z = map (\(x, y) -> (x * z, y)) l -- Specify the mix -- Syntax: ( -- [(fraction, product)], -- meals -- [(grams, product)] -- supplements -- ) -- WARNING: supplements must not seriously affect the energy value of the mix as they're omitted from the energy calculations fatsOilsM = [ (0.065, sunflowerOil), (0.025, flaxseedOil) ] plantM fats bulk = [ (0.695, bulk), (0.195, raisins), (0.02, parsleyDried) ] ++ fats -- TODO fix the /100 kludge electrolytesS = [ (5/100, naClI), (7/100, kCitrateH2O), (2/100, ca2CO3) ] electrolytesClS = [ (4/100, naClI), (3/100, kCl), (2.5/100, caCl2x2H2O) ] pPharmaS = [ (0.3/100, ascorbicAcid), (2, undevit) -- two pills ] myPharmaS = (3/100, fishOilCodLiver) : pPharmaS pharmaS = (1/100, cholineBitartrate) : myPharmaS seNutsS = (7/100, brazilNuts) kSelenateS = (250e-6/100, kSelenate) vigantolS = (10, vigantol) -- ten drops of vigantol on days w/o at least half an hour of good uvb light exposure nowD3S = (1, nowD35000) iodineS = (200e-6, naI) defaultS selenium = nowD3S : selenium : electrolytesS ++ pharmaS simpleR bulk selenium = Recipe (plantM fatsOilsM bulk) (defaultS selenium) l29ah :: Recipe l29ah = Recipe ((0.82, oat) :(0.15, soyflourdefatted) :fatsOilsM) (vigantolS :kSelenateS :(1, snK) :iodineS :electrolytesClS ++pPharmaS) recipes :: [(RecipeName, Recipe)] recipes = [("l29ah-raisins", Recipe ((0.81, oat) :(0.1, raisins) :fatsOilsM) (vigantolS :kSelenateS :(1, snK) :electrolytesClS ++pPharmaS)) ,("l29ah", l29ah) ,("l29ah-nosoy", Recipe ((0.91, oat) :fatsOilsM) (vigantolS :kSelenateS :(1, snK) :electrolytesClS ++pPharmaS)) ,("l29ah-choline", Recipe ((0.3, eggHardboiled) : attenuate (plantM fatsOilsM oat) 0.7) (vigantolS : kSelenateS : electrolytesClS ++ pPharmaS)) ,("default", l29ah) ,("default-choline", simpleR oat kSelenateS) ,("gluten-soy-free", Recipe ((0.94, buckwheatFlakes) :fatsOilsM) (vigantolS :kSelenateS :(1, snK) :electrolytesClS ++pPharmaS)) ,("gluten-free", Recipe ((0.88, buckwheatFlakes) :(0.07, soyflourdefatted) :fatsOilsM) (vigantolS :kSelenateS :(1, snK) :electrolytesClS ++pPharmaS)) ,("r2", Recipe (plantM fatsOilsM buckwheat) (nowD3S : kSelenateS : electrolytesClS ++ pPharmaS)) ] references :: [Nutrients] references = [рсн, fdardi, iomdrirda, iomdriul, lpi] -- Compare the mix against the reference comp :: Nutrients -> Nutrients -> Nutrients comp p ref = F.zipWith (/) p ref -- Compare the recipe against references tbl :: Recipe -> [Nutrients] tbl r = let nuts = sumNutrients $ fromRecipe r in nuts : map (\ref -> comp nuts ref) references -- Some pretty-printing printMass :: Double -> String printMass x | x > 2 = printf "%4.1f g" x | x > 2e-3 = printf "%4.1f mg" $ x * 1e3 | otherwise = printf "%4.1f µg" $ x * 1e6 printPercent :: Bool -> (Double -> Color) -> Double -> String printPercent useColors schema x | isNaN x = printf " " | otherwise = let value = (printf "%6.0f%%" x) in if useColors then colorify schema x value else value colorify :: (Double -> Color) -> Double -> String -> String colorify schema x s = concat [ setSGRCode [SetConsoleIntensity BoldIntensity, -- to be parseable by ansi2html and vivid in a real terminal emulator SetColor Foreground Dull (schema x)], s, setSGRCode [Reset]] good x = if x < 75 then Red else if x < 125 then Yellow else Green bad x = if x < 75 then Green else if x < 125 then Yellow else Red report :: Bool -> Recipe -> String report useColors rec = let [ pr, fa, carb, fib, k, na, ca, mg, ph, fe, i, zn, se, cu, cr, mn, mo, cl, fl, vA, vC, vD, vE, vK, thi, rib, nia, pant, vB6, bio, fol, vB12, cho, o3, o6, his, ile, leu, lys, met, phe, thr, trp, val, ala, arg, asn, asp, cys, glu, gln, gly, orn, pro, sel, ser, tyr, alaa, epa, dpa, dha, la, gla, aa ] = map (\(x:xs) -> x : map (* 100) xs) $ transpose $ map F.toList $ tbl rec in (printf "%-26s %14s %7s %7s %7s %7s %7s\n" ("" :: String) ("mass" :: String) ("РСН" :: String) ("FDA RDI" :: String) ("DRI RDA" :: String) ("LPI" :: String) ("DRI UL" :: String)) ++ concatMap (\(a, [w, b, c, d, e, lpi]) -> printf "%-26s %14s %s %s %s %s %s\n" a (printMass w) (printPercent useColors good b) (printPercent useColors good c) (printPercent useColors good d) (printPercent useColors good lpi) (printPercent useColors bad e)) ([ ("Protein", pr), ("Fat", fa), ("Carbohydrates", carb), ("Dietary fiber", fib), ("Potassium", k), ("Sodium", na), ("Calcium", ca), ("Magnesium", mg), ("Phosphorus", ph), ("Iron", fe), ("Iodine", i), ("Zinc", zn), ("Selenium", se), ("Copper", cu), ("Chromium (*)", cr), ("Manganese (*)", mn), ("Molybdenum (*)", mo), ("Chlorine", cl), ("Fluoride (*)", fl), ("Vitamin A", vA), ("Vitamin C (*)", vC), ("Vitamin D (*)", vD), ("Vitamin E", vE), ("Vitamin K", vK), ("Thiamin", thi), ("Riboflavin", rib), ("Niacin", nia), ("Pantothenic acid", pant), ("Vitamin B6", vB6), ("Biotin (*)", bio), ("Folate", fol), ("Vitamin B12", vB12), ("Choline", cho), ("Omega-3 fats", o3), ("Omega-6 fats", o6), ("Histidine", his), ("Isoleucine", ile), ("Leucine", leu), ("Lysine", lys), ("Methionine (a)", met), ("Phenylalanine (b)", phe), ("Threonine", thr), ("Tryptophan", trp), ("Valine", val), ("Alanine", ala), ("Arginine", arg), ("Asparagine", asn), ("Aspartic acid", asp), ("Cysteine (a)", cys), ("Glutamic acid", glu), ("Glutamine", gln), ("Glycine", gly), ("Ornithine", orn), ("Proline", pro), ("Selenocysteine", sel), ("Serine", ser), ("Tyrosine (b)", tyr), ("ALA (18:3 n-3)", alaa), ("EPA (20:5 n-3)", epa), ("DPA (22:5 n-3)", dpa), ("DHA (22:6 n-3)", dha), ("LA (18:2 n-6)", la), ("GLA (18:3 n-6)", gla), ("AA (20:4 n-6)", aa) ] :: [(String, [Double])]) ++ "(*) - see README\n" ++ "() - specified as the sum of components in IOM RDA" printRecipeItem :: (Amount, Source) -> String printRecipeItem (amount, (Source name cmp)) = printf "%-26s %14s\n" name (if isPill cmp then show amount else printMass $ amount * sServingMass cmp) printRecipe :: Recipe -> Double -> String printRecipe r days = "Recipe for " ++ show days ++ " days:\n" ++ (concatMap printRecipeItem $ attenuate (fromRecipe r) days) usage = do pn <- getProgName putStr $ usageInfo ("Usage: " ++ pn ++ " \navailable recipes:\n\n" ++ (unlines $ map fst $ recipes)) options data Flag = FReport | FColors | FDays Double deriving (Eq, Show) options :: [OptDescr Flag] options = [ Option ['r'] ["report"] (NoArg FReport) "print the nutrients report table" , Option ['c'] ["colors"] (NoArg FColors) "forcefully enable ANSI-colored output" , Option ['d'] ["days"] (ReqArg (FDays . read) "DAYS") "print the sources' masses counted for DAYS of consumption" ] main = do args <- getArgs let (opts, strings, errs) = getOpt RequireOrder options args supportsColors <- hSupportsANSI stdout let useColors = or [supportsColors, elem FColors opts] fromMaybe usage $ do recipename <- listToMaybe strings rec <- lookup recipename recipes let nrec = normalizeRecipe rec return $ do putStrLn $ report useColors nrec let days = maybe 1 (\(FDays d) -> d) $ find (\x -> case x of FDays _ -> True; _ -> False) opts when (notElem FReport opts) $ putStrLn $ '\n' : (printRecipe nrec days) ++ ("\nApproximate mass: " ++ (printMass $ (days *) $ sum $ map (\(amount, (Source _ cmp)) -> if isPill cmp then amount else amount * sServingMass cmp) $ fromRecipe nrec)) ================================================ FILE: README.md ================================================ # muesli A muesli calculator. Prints a recipe and its nutritional value. Brought up because i'm not much into spreadsheets and hoped to write some clever algo to sort the mix out for me someday. This project aims to provide one with nutritionally complete and easy to make food that needs to be chewed considerably to be consumed to trigger the corresponding digestive responses in one's body. There were also ideas about making it less bland for people unused to spice-free food, but i concluded it's quite individual stuff; i found sweeteners (like aspartame and sucralose), vanillin, apple flavoring, garlic or chili powder doing the job. It consumes about $1 and 15mins per day, excluding the research, for me. I believe in dogfooding, so you can check out the recipe i'm using at the moment by hitting `./Muesli.hs l29ah`. [ansi2html'ed snapshot of the recipe](http://muesli.l29ah.blasux.ru/muesli-dump.html) The current requirements are optimized for a median male. A female (or a frequent blood donor, or otherwise a person who loses erythrocytes quickly) would need to supplement iron additionally. TODO: requirement profiles If you found it useful, you're eating the muesli for a long time, or having any problems with it, drop me a line. ## Installation: * install ghc (9.2.0 or newer) and cabal-install * `cabal update && cabal install ansi-terminal fixed-vector` ## Usage: To see the nutrient profile and the current recipe, call: ``` $ ./Muesli.hs default ``` # What does it look like Raw: ![raw muesli](http://muesli.l29ah.blasux.ru/a.jpeg) Cooked: ![cooked muesli](http://muesli.l29ah.blasux.ru/b.jpeg) # Sources * [The original Soylent prototype](https://web.archive.org/web/20170305070025/http://robrhinehart.com/?p=424) * https://www.bestpravo.com/federalnoje/bz-dokumenty/c5o/index.htm * https://fdc.nal.usda.gov/fdc-app.html#/?query= * https://lpi.oregonstate.edu/publications/rx-health * Protein * should be 1,3-1,7g/kg body weight * 10.1123/ijsn.5.s1.s39 * https://www.ncbi.nlm.nih.gov/pubmed/16779921 * Calcium * [Calcium Supplementation in Clinical Practice: A Review of Forms, Doses, and Indications](https://onlinelibrary.wiley.com/doi/full/10.1177/0115426507022003286) * [Stimulates gastric acid secretion](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1411522/) * Magnesium * The IOM DRI UL is way too conservative, since at doses <2.5g the only side effect is possible mild diarrhea in some populations when supplemented * https://www.sciencedirect.com/science/article/pii/S2161831323013352 * https://ec.europa.eu/food/fs/sc/scf/out105_en.pdf * Potassium * https://www.nal.usda.gov/sites/default/files/fnic_uploads/water_full_report.pdf * Sodium * https://www.nal.usda.gov/sites/default/files/fnic_uploads/water_full_report.pdf * Chloride * no proper data from IOM * https://www.ahajournals.org/doi/full/10.1161/01.HYP.0000158264.36590.19 suggests chloride intake doesn't matter for blood pressure * Manganese * Opinion of the scientific committee on food on the tolerable upper intake level of manganese 19.10.2009 * manganese supplements are evil but no evidence of any damage from excessive intake from the food sources in diets of up to 20mg daily * https://discourse.soylent.com/t/have-you-asked-yourself-why-upper-limit-of-manganese-is-11mg-day/7660 * https://lpi.oregonstate.edu/mic/minerals/manganese#toxicity * I got 8µg/L whole blood Mn while consuming 20.1mg Mn from oats per day * Vitamin A * 1 IU = 300ng of retinol * EFSA [recommends 750μg retinol a day for adult men and 1300 for lactating women](https://efsa.onlinelibrary.wiley.com/doi/epdf/10.2903/j.efsa.2015.4028) * Dietary carotenoid bioavailability and conversion [is likely to be poor](https://pmc.ncbi.nlm.nih.gov/articles/PMC10261660/) * Vitamin K * green veggies * Vitamin C * https://academic.oup.com/ajcn/article/69/6/1086/4714888/ * ascorbic acid also retards fat rancidification * Vitamin D * comes from sunlight and supplements only, basically * quite a lot of inconclusive studies regarding cancer * amount * 1µg cholecalciferol = 40IU * https://www.sciencedaily.com/releases/2015/03/150317122458.htm * or even higher https://www.ncbi.nlm.nih.gov/m/pubmed/28768407/ * my own experience re D3 -> 25(OH)D3: https://bnw.im/p/0DLNGK * Biotin * Produced by body and generally abundant * https://en.wikipedia.org/wiki/Biotin_deficiency * Chromium * No cases of deficiency if not on long-term i/v feeding * https://en.wikipedia.org/wiki/Chromium#Biological_role * Molybdenum * Deficiency only on i/v feeding or in molybdenum-poor soils (northen China to Iran) * https://en.wikipedia.org/wiki/Molybdenum#Human_dietary_intake_and_deficiency * Iodine * Salt form is unnecessary, molecular iodine is okay * https://www.zrtlab.com/blog/archive/guide-how-to-treat-iodine-deficiency/ * 200µg I2 per 3L of water is 15-150 times less than used for drinking water disinfection * Fluoride * Controversial * https://en.wikipedia.org/wiki/Fluoride_deficiency * No effect on bone strength * https://www.ncbi.nlm.nih.gov/pubmed/8897754 * Seems to induce dental fluorosis at recommended dosages * https://www.ncbi.nlm.nih.gov/pubmed/2129630 * Likely neurotoxic when present in drinking water * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6923889/ * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3491930/ * Choline * synthesized by body in small amounts * i didn't observe the signs of deficiency myself although being low on it for like the whole life; tried refilling it with eggs for two weeks, didn't notice anything interesting * Fats * Polyunsaturated fatty acids * The oil should be unrefined, since refining converts some PUFAs into trans-isomeres. * https://www.sciencedirect.com/science/article/pii/S016378271300057X * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4179179/ * n-3 * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4179179/ * https://www.ncbi.nlm.nih.gov/pubmed/16841858 * DHA * brain (at least early and elderly); produced in small quantites from ALA in young females only * especially vulnerable to peroxidation in vivo: https://www.ncbi.nlm.nih.gov/pubmed/11110863 * Refined oil has a lower degree of peroxidation * https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4486537/ * Refined oil has much more trans fats * https://www.scielo.br/pdf/aabc/v79n2/a15v79n2.pdf ================================================ FILE: Setup.lhs ================================================ #!/usr/bin/env runhaskell > import Distribution.Simple > main = defaultMain ================================================ FILE: Types.hs ================================================ {-# LANGUAGE DataKinds, TypeFamilies, UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-tabs #-} module Types where import Data.Vector.Fixed.Boxed as V type Kcal = Double type Grams = Double type Elements = 64 type Nutrients = V.Vec Elements Grams data Component = Substance { sServingMass :: Grams -- the total mass of the component described by sNutrients , sNutrients :: Nutrients } | Pill { pNutrients :: Nutrients } deriving Show data Source = Source { sProdName :: String , sComponent :: Component } deriving Show type RecipeName = String type Amount = Double data Recipe = Recipe { rFoods :: [(Amount, Source)] , rSupplements :: [(Amount, Source)] } deriving Show ================================================ FILE: mktable.hs ================================================ #!/usr/bin/runhaskell {-# OPTIONS_GHC -fno-warn-tabs #-} import Data.List import Text.CSV llookup :: String -> [[String]] -> [String] --llookup hx [] = ["","g","WTF " ++ hx] llookup hx [] = [] llookup hx list = let (x:xs):ls = list in if x == hx then x:xs else llookup hx ls utoe "g" = "e0" utoe "mg" = "e-3" utoe "µg" = "e-6" tablify :: [String] -> String tablify (name:unit:amount:_) = amount ++ utoe unit tablify [] = "idk" lookups csv components = map (\c -> tablify $ llookup c csv) components -- Assume idk = 0 lookupFatty csv = sum . map (read :: String -> Double) . filter (/= "idk") . lookups csv components1 = ["Protein", "Total lipid (fat)", "Carbohydrate, by difference", "Fiber, total dietary"] components2 = ["Potassium, K", "Sodium, Na", "Calcium, Ca", "Magnesium, Mg", "Phosphorus, P", "Iron, Fe", "Iodine, I", "Zinc, Zn", "Selenium, Se", "Copper, Cu", "Chromium, Cr", "Manganese, Mn", "Molybden, Md", "Chloride, Cl", "Fluoride, F"] componentsPreFat = ["Vitamin A, RAE", "Vitamin C, total ascorbic acid", "Vitamin D (D2 + D3)", "Vitamin E (alpha-tocopherol)", "Vitamin K (phylloquinone)", "Thiamin", "Riboflavin", "Niacin", "Pantothenic acid", "Vitamin B-6", "Biotin", "Folate, total", "Vitamin B-12", "Choline, total"] componentsPostFat = ["Histidine", "Isoleucine", "Leucine", "Lysine", "Threonine", "Phenylalanine", "Threonine", "Tryptophan", "Valine", "Alanine", "Arginine", "Asparagine", "Aspartic acid", "Cystine", "Glutamic acid", "Glutamine", "Glycine", "Ornithine", "Proline", "Selenocysteine", "Serine", "Tyrosine"] omega3 = ["18:3 n-3 c,c,c (ALA)", "20:5 n-3 (EPA)", "22:5 n-3 (DPA)", "22:6 n-3 (DHA)"] omega6 = ["18:2 n-6 c,c", "18:3 n-6 c,c,c", "20:4 n-6"] sep = "\t" format comp csv = intercalate sep $ lookups csv comp main = do c <- getContents let cp = parseCSV "" c either print (\r -> do putStrLn $ format components1 r putStrLn $ format components2 r putStrLn $ (intercalate sep $ concat [ lookups r componentsPreFat, [show $ lookupFatty r omega3, show $ lookupFatty r omega6]]) putStrLn $ (intercalate sep $ lookups r componentsPostFat) putStrLn $ intercalate sep $ concat [ lookups r omega3, lookups r omega6] ) cp ================================================ FILE: mktable.sh ================================================ #!/bin/sh # Usage: $0 http://ndb.nal.usda.gov/ndb/foods/show/738?manu=&fgcd= curl -s 'https://ndb.nal.usda.gov/ndb/foods/show/'`echo "$1" | sed -e 's#[^0-9]*\([0-9]*\).*#\1#'`'?format=Full&reportfmt=csv' | iconv -f cp1251 | sed -e 's#^([^)]*)##' | ./mktable.hs ================================================ FILE: muesli.cabal ================================================ Name: muesli Version: 0 License: OtherLicense License-file: LICENSE Build-Type: Simple Cabal-Version: >= 1.2 Tested-With: GHC == 8.10.3 Executable Muesli Main-is: Main.hs ghc-options: -fno-warn-tabs other-modules: Database, DatabaseTools, Types, Muesli Build-depends: base >= 4 && < 5, ansi-terminal >= 0.6.2.1 && < 0.12, fixed-vector >= 1.1 && < 1.3