This is the first useful program I've written in the language of Bicicleta. It runs under the current Bicicleta available from http://pobox.com/~kragen/sw/bicicleta. (Older versions don't have working exponentiation.)
I think this is a *much* better example program than the factorial and such examples, because it shows how it's plausible to use it as the programming language for everyday tasks in an end-user programming system. #!./bicicleta_run_script # Icebox thermodynamics program. # I had done a bunch of calculations for a kragen-tol post (and # possibly a household project) about building an icebox to keep food # frozen. I kept having to change my assumptions and recalculate # things by hand. After I wrote the post, I realized that it would # have been better to write the calculations in Bicicleta, so I did. # It worked surprisingly well, but it takes an absurdly long amount of # time to run --- like 20 seconds. Doing the calculations in a # spreadsheet would have been a little less convenient; I could have # copied and pasted a range of cells and then made changes, but that's # a little less convenient as writing "less_stringent_freezer = # freezer { ice_kg = 16.0 }", and much more painful to understand # after the fact. # Example output: # "<p>Thermal insulators in general conduct heat at # about 0.04 W/m/K. Styrofoam is a better # insulator than some others; it conducts heat at about # 0.033 W/m/K.</p> # # <p>So let's consider building an icebox out of styrofoam. The idea is # that you put in some ice from some other source every so often, and # that ice keeps the icebox cold. If you salt the ice, it will melt # below the freezing point of pure water, so your icebox can be a # freezer.</p> # # <p>Suppose you want a 2. L of salted # ice in bottles to keep the temperature at -5°C for 24 hours # at a time. That means the total heat flux out has to be 2. L * # 80 kcal/L over those 24 hours, which is # 6.66666666667 kcal/h. (That's 7.75333333333 watts.)</p> # # <p>Suppose the interior of the freezer is # 250. L in a convenient cubical shape; that's a 62.9960524947-cm # cube, which has 2.38110157795 m² of surface area to lose heat through. # Suppose the outside air temperature is 35°C, for a # difference of 40 K. 0.033 W/m/K * 2.38110157795 m² * 40 K / # 7.75333333333 W = 0.405381008112 m of wall thickness, for a # total size of 1.44072254117 m, cubed.</p> # # <p>That's unwieldy, so suppose # you're willing to use more ice. Suppose you want a 16. L of salted # ice in bottles to keep the temperature at -5°C for 24 hours # at a time. That means the total heat flux out has to be 16. L * # 80 kcal/L over those 24 hours, which is # 53.3333333333 kcal/h. (That's 62.0266666667 watts.) # 0.033 W/m/K * 2.38110157795 m² * 40 K / # 62.0266666667 W = 0.050672626014 m of wall thickness, for a # total size of 0.731305776976 m, cubed. That's 7.64617160485 times smaller.</p> # # <p>Suppose that the outside # temperature is only 23°C on average. Now, to # melt the same amount of ice per day, the walls of the icebox that # melts 2. kg of ice per day can be 0.283766705679 m thick, and # the walls of the smaller icebox that melts 16. kg # of ice per day can be only 0.0354708382098 m thick. # # </p> # " {freezer: explanation = freezer.template % freezer template = "<p>Thermal insulators in general conduct heat at about {standard_insulator_conductivity} W/m/K. Styrofoam is a better insulator than some others; it conducts heat at about {styrofoam_conductivity} W/m/K.</p> <p>So let's consider building an icebox out of styrofoam. The idea is that you put in some ice from some other source every so often, and that ice keeps the icebox cold. If you salt the ice, it will melt below the freezing point of pure water, so your icebox can be a freezer.</p> <p>{heat_flux_paragraph}</p> <p>{shape_paragraph}</p> <p>{less_stringent_shape_paragraph}</p> <p>{more_normal_temperature_paragraph}</p> " standard_insulator_conductivity = 0.04 # W/m/K styrofoam_conductivity = 0.033 # W/m/K insulator_conductivity = freezer.styrofoam_conductivity heat_flux_paragraph = "Suppose you want a {ice_kg} L of salted ice in bottles to keep the temperature at {temp}°C for {hours} hours at a time. That means the total heat flux out has to be {ice_kg} L * {ice_heat_of_fusion} kcal/L over those {hours} hours, which is {heat_flux} kcal/h. (That's {heat_flux_watts} watts.)" % freezer ice_kg = 2.0 temp = 0 - 5 # °C hours = 24 # to melt that much ice ice_heat_of_fusion = 80 # kcal/L heat_flux = freezer.ice_kg * freezer.ice_heat_of_fusion / freezer.hours heat_flux_watts = freezer.heat_flux * freezer.kcalh_to_watts kcalh_to_watts = 1.163 # according to units(1) shape_paragraph = "Suppose the interior of the freezer is {capacity} L in a convenient cubical shape; that's a {cube_side_cm}-cm cube, which has {area} m² of surface area to lose heat through. Suppose the outside air temperature is {outside_temp}°C, for a difference of {temp_gap} K. {shape}" % freezer shape = "{insulator_conductivity} W/m/K * {area} m² * {temp_gap} K / {heat_flux_watts} W = {wall_thickness} m of wall thickness, for a total size of {total_size} m, cubed." % freezer capacity = 250.0 # liters cube_side_cm = freezer.cuberoot(freezer.capacity / 1000) * 100 # A function to calculate cube roots. # XXX mixed-mode 1 / 3.0 doesn't work yet cuberoot = {f: arg1 = 27.0, '()' = f.arg1 ** (1.0 / 3) } area = (freezer.cube_side_cm / 100)**2 * 6 outside_temp = 35 # °C temp_gap = freezer.outside_temp - freezer.temp # kelvins wall_thickness = freezer.insulator_conductivity * freezer.area * freezer.temp_gap / freezer.heat_flux_watts # note that due to lack of operator precedence, these parens are mandatory total_size = freezer.cube_side_cm / 100 + (freezer.wall_thickness * 2) less_stringent_shape_paragraph = "That's unwieldy, so suppose you're willing to use more ice. {less_stringent_heat_flux_paragraph} {less_stringent_shape} That's {volume_ratio} times smaller." % freezer less_stringent_freezer = freezer { ice_kg = 16.0 } less_stringent_shape = freezer.less_stringent_freezer.shape less_stringent_heat_flux_paragraph = freezer.less_stringent_freezer.heat_flux_paragraph volume_ratio = freezer.total_size**3 / (freezer.less_stringent_freezer.total_size**3) more_normal_temperature_paragraph = "Suppose that the outside temperature is only {more_normal_temperature}°C on average. Now, to melt the same amount of ice per day, the walls of the icebox that melts {ice_kg} kg of ice per day can be {thinner_walls} m thick, and the walls of the smaller icebox that melts {less_stringent_ice_kg} kg of ice per day can be only {less_stringent_thinner_walls} m thick. " % freezer more_normal_temperature = 23 # °C; lately the range has been 18-28 in_more_normal_temperature = freezer { outside_temp = freezer.more_normal_temperature } thinner_walls = freezer.in_more_normal_temperature.wall_thickness less_stringent_ice_kg = freezer.less_stringent_freezer.ice_kg less_stringent_thinner_walls = freezer.in_more_normal_temperature .less_stringent_freezer.wall_thickness }.explanation