text:
Readers like you keep news free for everyone.
More than 5,000 readers have already pitched in to keep free access to The Journal.
For the price of one cup of coffee each week you can help keep paywalls away.
Readers like you keep news free for everyone.
More than 5,000 readers have already pitched in to keep free access to The Journal.
For the price of one cup of coffee each week you can help keep paywalls away.
CALL IT SPACE grave robbery for a cause: Imagine scavenging defunct communication satellites for their valuable parts and recycling them to build brand new ones for cheap.
It's the latest pet project from the Pentagon's research wing known for its quirky and sometimes out-there ideas. The Defence Advanced Research Projects Agency is spending $180 million to test technologies that could make this possible.
When satellites retire, certain parts – such as antennas and solar panels – often still work. There's currently no routine effort to salvage and reuse satellite parts once they're launched into space.
DARPA thinks it can save money by repurposing in orbit.
"We're attempting to essentially increase the return on investment… and try to find a way to really change the economics so that we can lower the cost" of military space missions, said DARPA program manager David Barnhart.
Work on DARPA's Phoenix program – named after the mythical bird that rose from its own ashes – is already under way. The agency awarded contracts to several companies to develop new technologies, and it is seeking fresh proposals from interested parties next month.
A key test will come in 2016 when it launches a demonstration mission that seeks to breathe new life to an antenna from a yet-to-be-determined decommissioned satellite. DARPA has identified about 140 retired satellites that it can choose from for its first test.
Here's the vision: Launch a robotic mechanic outfitted with a toolkit that can rendezvous with defunct satellites and mine them for parts. The plan also calls for the separate launch of mini-satellites. The robotic mechanic would then string together the mini-satellites and old satellite parts to create a new communication system.
It's like doing robotic surgery in zero gravity.
DARPA officials said one way to keep costs down is for the mini-satellites to hitch a ride aboard available space on commercial rockets.
Harvard astrophysicist Jonathan McDowell, who tracks the world's space launches and satellites, called it "an interesting idea" that may reduce costs in the long-term.
"The first few times you do this, it'll definitely be more expensive than just building the new antenna on your satellite from scratch. But in the long run, it might work out," he said in an email.
McDowell said the biggest challenge in the upcoming demo test is separating the antenna from the retired satellite without breaking it and then successfully integrating it with the mini-satellites.
DARPA is used to funding blue-sky research and a few projects are slowly becoming reality.
In 2011, it dangled seed money to jumpstart a way to rocket people to a star within a century in what's known as the 100-year Starship program.
Long before Google tested self-driving cars, DARPA sponsored a robotic road race in which university-designed autonomous vehicles eyed for the finish line without human help.
To embed this post, copy the code below on your site


text:
Best Escorts In Hazelwood, Missouri
Looking for an older woman in Hazelwood for some outdoor sex
Best Escorts In Hazelwood, Missouri
First name: Isalie, Age: 44 yo, City: Hazelwood (MO)
To be honest, I don't really have a type when it comes to one night stands. However, it is important that this lover be very without taboos. I love long foreplay because I enjoy being desired before we make love. I'm a girl who's good at sucking to make you hard. Otherwise I like to try unusual sexual practices, for example anal sex. I want to meet you at your apartment because I need to be very discreet. I am also available in the afternoon for this adulterous meeting. I am waiting for your offers with interest. I can't wait for our first meeting, it's always aphrodisiacal to me... kisses Isalie.
One night stand Hazelwood: hot woman with no taboos
Best Escorts In Hazelwood, Missouri
First name: Marie-violaine, Age: 27 yo, City: Hazelwood (MO)
Hi everyone, my name is Marie-violaine and I'm single, I'm only 27 years old. I am very sexy. And I'm really good at fucking. I am free at the beginning of the week and prefer to be available at the end of the day. You can find yourself wherever you want, but around Hazelwood. In my ideal, I would like the men who contact me to be blond and preferably tall. The boy I'm looking for must be good in bed because I expect a lot from him sexually. I can stay in bed all weekend if my partner knows what they're doing. I love cunnilingus because it makes me very wet. I'm a very naughty young woman when I fuck with a good guy. In short, to be sexually satisfied it's better not to be a novice. If you meet my expectations, you won't be disappointed.
A cool couple on Hazelwood wants to start in the libertinage
Best Escorts In Hazelwood, Missouri
First name: Ahou, Age: 38 yo, City: Hazelwood (MO)
Hello naughty ones, I am Ahou and I just turned 38. My husband is 36 years old and we are quite hot. I want a charming and libertine guy who will make me come with my boyfriend because I am a naughty woman who likes to have 2 cocks for herself. We suggest you set up a date in a swingers club to help you find each other. We're finally available in the late afternoon. We enjoy spending evenings in libertine clubs on Hazelwood to meet different couples. It's mainly for me because I'm tireless with men and I have no taboos. Now we want to discover your hottest advances. I look forward to reading your messages. Kisses! See you soon.
A young woman who enjoys public exhibitionism is meeting up in a park
Best Escorts In Hazelwood, Missouri
First name: Maryannick, Age: 24 yo, City: Hazelwood (MO)
To see each other, it is possible to go to my house or the restaurant. I am available on weekends, I'm not contrary. In my ideal, I would like the boys who contact me to be brown and rather tall. I'm looking for a man who can keep up with me in the bedroom. I have a high sex drive and need someone who can match my energy. I love staying in bed all weekend, if my partner knows how to handle it. I'm a girl who loves giving good blowjobs to get you really excited. I also don't say no when it comes to testing out unusual sexual practices, like anal sex. So, I'm looking forward to reading your comments. I hope to meet you. I'm sure we'll have a great time during this naughty date. Good job! Big kisses.
Looking for a hot afternoon fuck in Hazelwood
Best Escorts In Hazelwood, Missouri
First name: Domino, Age: 20 yo, City: Hazelwood (MO)
The easiest way to set up a meeting for this hookup is at my place. I am also available mostly at the end of the day and rather on weekends. I'm a girl who likes to suck so you have a nice erection. Otherwise I like to try unusual sexual practices like anal sex. I want a guy with a really big penis. Someone to have a great time with without any hassle. To finish, I hope to have some hot hookups with a libertine. You must contact me first. I hope to meet you soon! Kisses.
Pretty 18-year-old girl on Hazelwood looking for a lover for dirty games
Best Escorts In Hazelwood, Missouri
First name: Ysoline, Age: 18 yo, City: Hazelwood (MO)
Hello, I wanted to post my naughty desires on this hookup site for fun. So my name is Ysoline, I'm 18 years old. I'm a nympho girl who loves to pick up guys for a cam plan. I'm attracted to sexier guys. I also want a guy with a big dick because otherwise I don't feel anything. I absolutely need to have an orgasm. A one night stand should make me shiver. I want an h who is a good cunnilingus. Other than that, I'm a fan of anal sex but with tact. I'm not against a date in nature if you like it. I want a lover who will take charge during our sexy encounter. I'm only here to get laid. To meet up, I'm available in the afternoon. You can choose the place but only on Hazelwood. If you're feeling frisky, why not shoot me a naughty message? I hope to give you an appointment on Hazelwood for this fuck. Kisses. See you later.
Looking for a mature woman who needs some action Hazelwood
Best Escorts In Hazelwood, Missouri
First name: Ninnog, Age: 41 yo, City: Hazelwood (MO)
I'm generally free to meet up with you for a date in the early afternoon. We can see each other on Hazelwood and its surroundings. I'm looking for a guy who is younger than me. I don't have a criterion of beauty. What I want is a man who's good in bed so that he can make me scream during our future night of sex. I love the practices of libertinism. I've always been a woman who loves swinging and exhibitionism in particular. It turns me on when couples watch me masturbate in public places like rest areas. I want to be in the company of this man who can do all my naughty games. I'm excited to read your comments. Looking forward to seeing you, kisses. See you soon.
Nana in a relationship would like to try out côte-à-côtisme at a libertin club on Hazelwood
Best Escorts In Hazelwood, Missouri
First name: Immaculee, Age: 43 yo, City: Hazelwood (MO)
You can have a meeting at our apartment, but if you prefer we can travel to Hazelwood and its surroundings. For this future threesome we are free essentially in the early evening. We are only looking for a naughty man to engage in some swinging. Age is not a requirement, but respect is always required to sleep together. We've been passionate about naughty games for a while now. My boyfriend and I try new experiences between libertines regularly, lately it's exhibitionism. If you like our naughty ad, please contact us. We are very excited to be on this libertine dating site. See you soon.
Young woman around Hazelwood looking for several mature pigs to try out libertinism
Best Escorts In Hazelwood, Missouri
First name: Exilie, Age: 32 yo, City: Hazelwood (MO)
I love it when someone goes down on me because it feels amazing. I'm a young woman who gets particularly hot when I'm with a stranger. I like really cute guys. I also demand a well-built H because otherwise I don't feel anything. I just want to enjoy myself like never before. I agree to meet in the city center for this future hookup. I am also available mostly at night and rather on weekends. Of course, I invite you to contact me quickly if you are considering fucking me. I demand a man perverse enough. See you soon.
My wife is hot and she wants a threesome tonight
Best Escorts In Hazelwood, Missouri
First name: Leyah, Age: 18 yo, City: Hazelwood (MO)
Hi there, we're a naughty couple and live in Hazelwood. My name is Leyah and I am 18 years old. My h is 19 years old. We are available on weekends to invite you. You can take care of yourself here. We've been into swinging for quite a while now. My boyfriend and I have been exploring some new kinky things lately, like swinging. Our ideal would be a guy around the same age for this date between swingers. I'm a fun-loving girl and I need a real man to have some fun with. Now, we're waiting to receive your dirtiest desires. I look forward to reading your comments. Kisses! See you soon.
- Best Escorts In Elm Grove, Wisconsin
- Best Escorts In Los Alamitos, California
- Best Escorts In Bellevue, Wisconsin
- Best Escorts In Asbury Lake, Florida
- Best Escorts In Merrifield, Virginia
- Best Escorts In San Juan Capistrano, California
- Best Escorts In Montvale, New Jersey
- Best Escorts In Yucaipa, California
- Best Escorts In Denver City, Texas
- Best Escorts In Lake Carmel, New York
- Best Escorts In Pagosa Springs, Colorado
- Best Escorts In Lucas Valley-Marinwood, California
- Best Escorts In Bradley Gardens, New Jersey
- Best Escorts In Clarkston Heights-Vineland, Washington
- Best Escorts In Plain City, Ohio
- Best Escorts In Winchester, Indiana
- Best Escorts In Red Oak, Iowa
- Best Escorts In Hopewell, Virginia
- Best Escorts In Winslow, Arizona
- Best Escorts In Decatur, Alabama

subset: commoncrawl


text:
Presumably for two reasons. The first is that the true account of events undercut the president's claim during the campaign that al Qaeda was severely weakened in the aftermath of the killing of Osama bin Laden. The second is that a true account of what happened in Benghazi that night would have revealed that the president and his top national-security advisers did not treat a lethal attack by Islamic terrorists on Americans as a crisis. The commander in chief not only didn't convene a meeting in the Situation Room; he didn't even bother to call his Defense secretary or the chairman of the Joint Chiefs of Staff. Not a single presidential finger was lifted to help Americans under attack.
This is an embarrassment and a disgrace. Is it too much to hope that President Obama is privately ashamed of his inattention and passivity that night?I think he is ashamed. Here's what I've been assuming happened: It looked like our people were overwhelmed and doomed, so there was shock, sadness, and acceptance. But then the fight went on for 7 or 8 hours. The White House folk decided there was nothing to do but accept the inevitable, and then they witnessed a valiant fight which they had done nothing to support. It was always too late to help. It was too late after one hour, then too late after 2 hours, then too late after 3 hours.... When were these people going to die already? After that was all over, how do you explain what you did?
IN THE COMMENTS: CWJ said:
Althouse's surmised timeline if true is the ultimate in —
"What difference, at this point, would it make?"
Perhaps Hillary was telling us more than met the eye.


text:
Skip to main content
Click Here
Visit Covid Resource Center
Welcome to the GeoWarehouse Blog
GeoWarehouse Training at Your Fingertips
Choose a Blog Category
Select Category
Accurate Square Footage
Aerial Imagery
Appraisal Fraud
Appraisal Technology
Asset Investigation
Automated Valuations Models
Average House Price in Canada
Bank of Canada rate announcement
BOC Interest Rate
BOC Rate Increase
Canada Day
Canadian Home Prices
Canadian Hommeowners
Canadian Interest Rates
Canadian Mortgage Awards
Canadian Mortgage Rules
Canadian Real Estate Industry
Canadian Real Estate Market
Canadian Real Estate Professionals
Collection Enforcement
Commercial Real Estate Tips
Comparable Sales Search
Condo Liens
Condo Status Certificate
Condo Status Search
Coronavirus Canada
CRA cracking down on condo buyers
Customer Relationship Management
Cutting your Expense Budget
Debt Recovery
Demographic Information
Difference Between Geowarehouse and Vimo
Digital Open house
Digital Signature
Due Diligence in Real Estate
Electronic Purchase and Sales Agreement
Enhanced Sales Report
First Time Homebuyers
Foreign Buyer Tax
Fraud Awareness Month
Generating Real Estate Leads
GeoWarehouse Announcement
Geowarehouse Customers
GeoWarehouse eBook
GeoWarehouse News
Geowarehouse Reports
GeoWarehouse Store
GeoWarehouse Training
GeoWarehouse® Service Interruption
Giving Back
Government of Ontario
Greater Toronto's Top Employers
Happy Holidays from GeoWarehouse
Heat Maps
Helping Seniors
Helping the Buyer
Home Insurance Claim
Home Ownership Search
Home Valuation
Home Value Range
House Price Index
Housing Affordability
Housing Market
Improve Closure Rates
Inman Agent Reboot
Instrument Image
Instrument Images
Insurance Claims History Report
Interest Rate Increase
Interest Rates
Investing in Real Estate
Jobs in Real Estate
Kobo Contest for Ontario Real Estate Sales Professionals
Land Registry
Land Surveys
Landing Good Real Estate Deals
Legal Home Owners
Legal Property Owner
Listing Price
Map Search
March 2018 Teranet Market Insights Report
Market Insights Report
Millennials and Real Estate
MLS Listing Search
Mobile Apps
Mobile Apps for Real Estate
Mobile Apps that help Real Estate Sales Professionals
Mobile Technology
Mortgage Awards of Excellence
Mortgage Rates Increase
MPAC Assessments
MPAC Property Details Report
Municipal Address
Neighbourhood Demographics
Neighbourhoods in Toronto
New GeoWarehouse
New Mortgage Rules
Newcomers to Canada
Non Resident Speculation Tax
Obtain a Property Survey
online condo certificates
Online Property Survey
Online Real Estate Forms
Online Real Estate Searches
Ontario closing costs
Ontario Real Estate Professionals
Ontario Real Estate Professionals LinkedIn Group
Open House
Paperless Real Estate
Parcel Register
Pinterest Marketing
Preventing Real Estate Fraud
Private Investor
Property Appraisal
Property Details Report
Property Images
Property Information
Property Investigation
Property Investment Tools
Property Report
Property Sales History
Property Search
Property Survey
Property Title Search
Property Valuation
Property Value
Protect Your Boundaries Reports
Real Estate
Real Estate and Business Brokers Act
Real Estate Apps
Real Estate Branding
Real Estate Comparables
Real Estate Day
Real Estate Developers
Real Estate Events
Real Estate Fraud
Real Estate Law
Real Estate Lead Generation
Real Estate Leads
Real Estate Listing
Real Estate Market
Real Estate Marketing
Real Estate Marketing Tips
Real Estate News
Real Estate Opportunities
Real Estate Predictions
Real Estate Pricing Strategy
Real Estate Pulse
Real Estate Reports
Real Estate Sales
Real Estate Sales Professionals
Real Estate Technology
Real Estate Tools
Real Estate Training
Real Estate Transactions
Real Estate Trends
Representing Divorcing Spouses
Residential Detailed Report
Residential Relocation Reports
Sales Comparables
Seminar for Real Estate Sales Professionals and Mortgage Professionals
Spring Housing Market
Status Certificate
Straw Buyers in Real Estate
Syndicated Mortgages
Team Member Spotlight
Teranet Announcement
Teranet Insighters
Teranet Market Insight Forum
Teranet Market Insights Report
Teranet Monthly Market Insights Report
Teranet Real Estate Trends
Teranet-National Bank House Price Index
Title Insurance
Title Search
Toronto Condo Real Estate
Toronto Real Estate Market
Toronto's Top Employers
TREB Market Watch
Uncover A Lien
validate information
Validating Homeownership Information
Verifying Home Ownership
Virtual Home Sales
Virtual Mobile Office
Visual Branding
Winter Real Estate Listings
Year Built Information
Never Let a Missing Property Survey Stall Your Closing
Does Your Client Need a Property Survey? It May Be Available Online
Online Property Survey
Access the NEW GeoWarehouse e-Store and Win a $500 Best Buy Gift Certificate
Condo Status Certificate
The Survey Says… Property Survey That Is
Property Survey
Online Real Estate Searches – 3 Searches You May Not Know Are Available in the GeoWarehouse Store
Online Real Estate Searches
No Property Survey? No Problem
GeoWarehouse Store
Yes! You Can Obtain a Property Survey for Your Client Online!
Land Surveys
Why is Having Access to a Property Survey So Important?
Property Survey


text:
February 15, 2008
Riots in Denmark
Gateway Pundit has a summary.
I've lived through exactly one set of riots (okay, okay: two—I was quite young during the Watts riots, and I lived many miles away in Whittier, so I was far from the flames).
But during the Rodney King riots in 1992, the saving grace was that some people had guns, and were able to defend their lives and property when they absolutely had to.
I know England has largely given up on there being a fundamental right to self-defense‐even when guns aren't used at all (for instance, when one uses any sort of blunt instrument against an attacker—this is often prosecuted.)
But has the rest of Western Europe done so as well? And when the veneer of civilization wears thin—as it does everywhere, from time to time—what recourse does the common person have against these, um, overly exuberant "youths"?
Self-defense isn't simply a human right; it is the human right.
h/t to Dean Esmay, who's been carrying the button/legend about self-defense forever. It always struck me as a fundamental truth.
He wrote this years ago (though you can't tell), but, in addition to Esmay carrying the button, here's the wonderful Mark Steyn throwing a verbal beating to the British legislature over the God given right to self defense.
"Let the issues be the issue.
About Joy W. McCann: I've been interviewed for Le Monde and mentioned on Fox News. I once did a segment for CNN on "Women and Guns," and this blog is periodically featured on the New York Times' blog list. My writing here has been quoted in California Lawyer. I've appeared on The Glenn and Helen Show. Oh—and Tammy Bruce once bought me breakfast.
My writing has appeared in The Noise, Handguns, Sports Afield, The American Spectator, and (it's a long story) L.A. Parent. This is my main blog, though I'm also an alumnus of Dean's World, and I help out on the weekends at Right Wing News.
My political philosophy is quite simple: I'm a classical liberal. In our Orwellian times, that makes me a conservative, though one of a decidedly libertarian bent.
An American Carol rawks!
Main AAC site (Warning: sound-enabled;
trailer starts automatically.)
Buy Blogads from the
Network here.
This is one of the last pix
we took before we left
the house in La Cañada.
I think it's very flattering
to Bathsheba the .357.
"The women of this country learned long ago,
those without swords can still die upon them.
I fear neither death nor pain." —Eowyn, Tolkien's
Lord of the Rings
Free Abdulkarim al-Khaiwani!
See Jane Novak's "Yemeni Watch" blog,
Armies of Liberation.
Free journalists and dissident bloggers, worldwide!
Some of My Homegirls— ERROR: http://rpc.blogrolling.com/display_raw.php?r=59e4b55f70f50de810150859b200a635 is currently inaccessible
• API (Information on Oil and Natural Gas)
• Natural Gas
• The California
Energy Blog
• The Alternative Energy Blog
(Solar, Wind, Geothermal, etc.)
• The Energy Revolution Blog
• Gas 2.0 Blog
• Popular Mechanics'
"Drive Green"
• Libertas
(now on hiatus, but they'll be back!) • Pajiba
Real Indie Productions—
• Indoctrinate U
(Evan Coyne Maloney)
• Mine Your Own Business
(Phelim McAleer)
• Expelled: No
Intelligence Allowed
(Ben Stein, Logan Craft,
Walt Ruloff, and John
Real Indie Production
and Distibution
• Moving Picture Institute
• First Installment: The Basic Story
• Hymers' History of Violence
• How Fun Is It To
Be Recruited Into Hymer's
Offbeat Church? Not Very. • How I Lost My Virginity
On Food:
• Dreadful Breakfast Cookies
On Men and Women:
• It's Rape If
You Don't Send
Me Money
• Women Talk Too Much;
I'll Date Dolphins
• Heterosexual
Men Are Kinky
• Hot Cars,
Hot Girls
On Animation:
• Freakazoid!
—the Commentary
• Freakazoid!
On Religion:
• Athiests and
Christians Talking
To Each Other
"Good grammar, and better gin."
—CalTech Girl
"I enjoy Little Miss Attila's essays."
—Venomous Kate
"Joy is good at catching flies with honey."
—Beth C
"Your position is ludicrous, and worthy of ridicule."
—Ace of Spades
—Suburban Blight
Teh Funny—
• Dave Burge
Interesting News Items
Civics Lessons—
Taranto on How a Bill Becomes Law
Editorial Resources—
• Better Editor
• Web on the Web
• Me me me me me! (miss.attila --AT-- gmail --dot-- com)
• Cigar Jack
• David Linden/
The Accidental Mind
• Cognitive Daily
Rive Gauche—
• Hip Nerd's Blog
• K's Quest
• Mr. Mahatma
• Talk About America
• Hill Buzz
• Hire Heels
• Logistics Monster
• No Quarter
Food & Booze—
• Just One Plate (L.A.)
• Food Goat
• A Full Belly
• Salt Shaker
• Serious Eats
• Slashfood
• Things You Should Do
(In the West)
• Just One Plate (L.A.)
• • Jalopnik
The Truth About Cars
SoCal News—
• Foothill Cities
Oh, Canada—
• Five Feet of Fury
• Girl on the Right
• Small Dead Animals
• Jaime Weinman
• Mary McCann,
The Bone Mama
(formerly in Phoenix, AZ;
now in Seattle, WA;
eclectic music)
• Mike Church,
King Dude
(right-wing talk)
• Jim Ladd
(Los Angeles;
Bitchin' Music
and Unfortunate
Left-Wing Fiddle-Faddle)
• The Bernsteins
(Amazing composers
for all your
scoring needs.
Heh. I said,
"scoring needs.")
Iran, from an Islamic Point of View
and written in beautiful English—
• Shahrzaad
• Blogging Away Debt
• Debt Kid
• Debtors Anonymous
World Services
• The Tightwad Gazette
• Gentleman Pornographer
More o' Dat
Pop Culture—
• Danny Barer
(Animation News) • Something Old,
Nothing New
(And yet more
Animation News)
• Sam Plenty
(Cool New
Animation Site!)
• The Bernsteins
(Wait. Did I mention
the Bernsteins
already? They're
Guns & Self-Defense— • Paxton Quigley, the Pioneer •TFS Magnum (Zendo Deb) •Massad Ayoob's Blog
The American Mind
Aces, Flopping
Ace of Spades
Armies of Liberation
Asymmetrical Information
Atlas Shrugs
Attila of Pillage Idiot
Beautiful Atrocities
The Belmont Club
The Bitch Girls
Books, Bikes, and Boomsticks
The Common Virtue
Da Goddess
Danz Family
Dean's World
Desert Cat/a>
Digger's Realm
Cam Edwards
Eleven Day Empire (James DiBenedetto)
Flopping Aces
Froggy Ruminations
Gay Orbit
Jeff Goldstein
Mary Katherine Ham
At the D.C. Examiner Hugh Hewitt
Hi. I'm Black.
Iberian Notes
The Irish Lass
In DC Journal
Infinite Monkeys
Intel Dump
Trey Jackson (videoblogging)
James Joyner
James Lileks
Rachel Lucas
Men's News Daily
Michelle Malkin
Nice Deb
No Watermelons Allowed
North American Patriot
On Tap
On the Fritz
On the Third Hand
Outside the Beltway
Peoria Pundit
Photon Courier
Power Line
The Protocols of
the Yuppies of Zion
Protein Wisdom
The Queen of All Evil
Questions and Observations
Right Wing News
Donald Sensing
Rusty Shackleford
The Shape of Days
Sharp as a Marble
Sheila A-Stray
Laurence Simon
Six Meat Buffet
Spades, Ace of
Suburban Blight
TFS Magnum
This Blog is Full of Crap
The Truth Laid Bear
Venomous Kate
The Volokh Conspiracy
Where is Raed?
Write Enough
You Big Mouth, You!
Support our troops; read the Milblogs!
Support a Blogger
at the LinkGrotto.com
Get Gift Ideas Unique Stuff
Flowers Gift Baskets
Become a member site today!


text:
This section contains information on documentation content changes that were made in this Standard Edition Getting Started Guide for Novell ZENworks 10 Configuration Management SP3. The information can help you to keep current on updates to the documentation.
The documentation for this product is provided on the Web in two formats: HTML and PDF. The HTML and PDF documentation are both kept up-to-date with the changes listed in this section.
If you need to know whether a copy of the PDF documentation that you are using is the most recent, the PDF document includes a publication date on the title page.
The documentation was updated on the following date:


text:
There are many reasons one could argue that the PC is the best way to play video games: Better visuals, cheaper and more interesting games, a wide-open platform, and so on. But one of the best arguments for PC gaming is simple: The massive back-catalogue.
No other gaming platform can field a game library that can compete with PC's in terms of sheer volume. The PC boasts more than 20 years' worth of video games, most of which are still playable on modern PCs, given a tweak or two. Now, it's time to put all of the best classic PC games in one place.
Rather than approach this like a Kotaku Bests list, I thought we'd try something different—turn it over to you, as well as our other Kotaku editors, to create one superlist to unite them all.
First, a few ground rules. I'd love to make this into a list that reflects the taste of the Kotaku readership in the best, most readable way possible, so let's all follow the same format. In addition, you can find general tips and techniques for Kotaku commenting here.
1. Only games from 2003 and earlier. The last ten years is still too current to qualify for a "classics" list. Hey, we had to draw the line somewhere!
2. Please don't leave non-entry, direct comments on this post. They'll just get pushed down. Save your comments for others' submissions.
3. All entries must be legally purchasable. We'd prefer you include games that are easily available digitally, but if you must include a game that is difficult to find, link to the eBay and Half.com pages (or similar sites) to help people find cheap used copies. Any comments linking to torrent/piracy sites will be removed.
4. Avoid dupes. If someone's beaten you to your favorite classic game, please avoid making a second entry for it. Instead, chime in beneath their comment to add your own take on the game, your own images, your own memories and videos. It's true that this approach will favor those who read and act quickly, but it's also the best way to get a list that is easily scannable and doesn't have 12 entries for Deus Ex. (Which I actually already wrote up. Heh. Sorry.)
5. Follow this format for your entries, including bold text:
IMAGE [preferably at 970x546]
[Game Name]
Why: Explain why the game is great. Make your case! Try to keep it to a single paragraph, maybe two. Feel free to include a video example, if that helps.
Where you can get it: Put all the places you can get a copy, with a link if possible. eBay, Half.com, other places for used copies of games that aren't available digitally.
Tips for modern machines: Lots of classic games have a few tweaks that'll make them run better on modern machines. Include those here, along with any links to forum posts summing up which patches to include. Links to HD mods, other user-created fixes and content are also great!
When in doubt, check the entries that our writers have done. They should all be in the proper format.
If we get some good entries, we might break them out and run them as their own posts on Kotaku. (No promises, though.)
Okay, let's make a megalist for the ages. What are the classic PC games everyone must play?
UPDATE: For a complete alphabetical directory of all the entries on this list, go here.


text: by David Crane [email protected] DefRev's been hearing some good things about this item. The Surefire X200 LED WeaponLight is Surefire's latest handgun-mounted tactical light, and it's designed to go head-to-head against Insight Technology's M3 group of tactical weapons lights. These include the M3 Tactical Illuminator, M3-LED Tactical Illuminator, and M3X Tactical Illuminator. DefRev has yet to T&E the Surefire X200 …Read More »


text:
Climate change will make commercial shipping possible from North America to Russia or Asia over the North Pole by the middle of the century, a new study says.
Two researchers at the University of California ran seven different climate models simulating two classes of vessels to see if they could make a relatively ice-free passage through the Arctic Ocean. In each case, the sea routes are sufficiently clear after 2049, they say.
The study, published Monday in the journal PNAS by Laurence C. Smith and Scott R. Stephenson, found that the sea ice will become thin enough that a "corridor directly over the north pole" will open up. "The shortest great circle route thus becomes feasible, for ships with moderate ice-breaking capability."
(A great circle route is the shortest distance between two points on the surface of a sphere, such as the Earth.)
Smith and Stephenson conclude that the opening of the new routes "heightens the urgency for a mandatory International Maritime Organization regulatory framework to ensure adequate environmental protections, vessel safety standards, and search-and-rescue capability."
According to The Guardian:
"The northern sea route has been shown to save a medium-sized bulk carrier 18 days and 580 tons of bunker fuel on a journey between northern Norway and China. Shipowners have said it can save them €180,000-€300,000 ($235,000-$390,000) on each voyage. A direct route over the pole could save up to 40 percent more fuel and time."
Copyright 2016 NPR. To see more, visit http://www.npr.org/.


text:
Venice Mini Necklace
Or 4 installments of $16.25 by afterpay Learn more about Afterpay
Estimated Delivery : Oct 05 - Oct 06
FREE Shipping
- 18kt gold-plated brass
- Made in China
- Lobster clasp closure
- Measures approx 16" in length
- Revolve Style No. GORJ-WL1135
- Manufacturer Style No. 212-103-G
Equally beach casual and city chic, Gorjana is a socially conscious lifestyle brand that makes fashionable, high quality accessories for women. Their signature dainty stackable pieces are both understated and eye catching all in one. Layer them up and you'll never want to take them off again.
Style It With
If an item you would like to purchase is out of stock, you can place a Special Order Inquiry. REVOLVE will then check the availability and obtain an approximate arrival date for the item, if available. Typically, it takes up to 3-4 weeks to verify this information.
Placing a Special Order Inquiry is absolutely free and there is no obligation to follow through with a purchase.
- You will be notified by email once we receive the item.
- You may cancel at any time without penalty
- Your card will ONLY be charged when your order is shipped.
- Availability is not guaranteed.


text:
ESPN's announcement Wednesday that it will shut down its 3-D channel by the end of the year is the latest sign the format won't revolutionize entertainment as the industry once hoped.
Troubling signs for 3-D have been on the horizon for a last year or so. ESPN 3D's audience ratings were below The Nielsen Co.'s measurable threshold, and in March, the Motion Picture Association said box office revenue for 3-D showings in the U.S. and Canada was flat in 2012 from a year earlier at $1.8 billion. The number of 3-D films released in the period dropped by 20 percent.
"The ESPN decision is a sign that the 3-D ecosystem is not healthy," said Laura Martin, an analyst with investment banking firm Needham & Co. "It must be there's not enough demand for 3-D TV."
The sports network said there weren't enough viewers to make 3-D broadcasts worth it. It didn't say exactly how many viewers it had, but the number was "extremely limited and not growing," the network said.
Last year, an estimated 6 percent of TVs in the U.S. were able to show 3-D programming, according to the most recent data from research firm IHS Screen Digest. Even homes that have 3-D TVs don't appear to be using them very much, said IHS analyst Sweta Dash.
The lack of programming and the discomfort of having to wear special glasses could be contributing to the problem, she said.
"It's not convenient for people to watch for hours and hours with glasses," Dash said. "They get tired."
ESPN 3D launched in 2010 as one of nine 3-D channels that followed the release of James Cameron's blockbuster film, "Avatar." TV makers rushed to introduce 3-D sets as well. ESPN said at the time that it expected a "3-D tsunami" in the industry.
3net, a 24-hour-a-day 3-D channel that launched in February 2011 under the ownership of Sony Corp., Discovery Communications Inc. and Imax Corp., appeared to be unfazed by ESPN's announcement.
"Although we don't comment on the activities of other companies, their decision has no impact on our business," the venture said in a statement.
IHS's analyst Dash said there appears to be a bigger appetite for 3-D TVs overseas in markets such as China.
TV manufacturers have recently switched their focus from 3-D to "ultrahigh definition," a format that increases the pixel count of high-definition TVs by four times.
At the International Consumer Electronics Show in January, companies like Sony, LG Electronics Inc., Sharp Corp., and Samsung Electronics Co. all showed off so-called "ultra HD" sets that were meant to be within the price range of middle income early adopters. Sony's 55-inch model sells for $5,000.
One benefit of the ultra HD format is that viewing doesn't require special glasses, and because people can sit closer to the screen without a loss in quality, bigger screens can replicate the immersion of 3-D video.
Ultra HD is also easier to handle on the production end.
With 3-D TV, two cameras have to be rigged together on a special mount to create the 3-D effect. And because viewers can get dizzy with quick cuts, camera operators specialized in 3-D stay focused on single shots for longer. That makes it hard for producers to simply use "one eye" of a 3-D camera for 2-D broadcasts. Instead, camera positions and personnel costs were just multiplied for events shot in both formats.
Along with higher costs, any viewing on 3-D platforms draw viewers away from the standard broadcast, said Rob Willox, director of large sensor technology for Sony Electronics, in an interview last month about the differences between the two formats.
"There are a lot more costs, and you're not increasing audience share, you're dividing it," he said.
In contrast, ultra HD video is more easily scaled down to regular HD, meaning that high-end cameras can be used for viewers watching on TVs of either standard.
Even as it made plans to close down its 3-D channel, ESPN said it was a leader in 3-D productions, having produced 380 events in 3-D over the last 3 years.
"Nobody knows more about sports in 3-D than ESPN, and we will be ready to provide the service to fans if or when 3-D does take off," it said in a statement. "We continue to experiment with things like ultrahigh definition."


text:
7 Premium Pro Presets
This 7 presets , are good for each photo you like.
In the zip file you will find a help.txt + 7 presets.
Compatible file types: RAW, JPG, PNG
These presets has been successfully tested with Adobe Lightroom 4.1 Under exposed or over exposed images may not give you the best result.
Enjoy , and if you like it, don't forget to rate it.


text:
1. Washing: Wash inside out with cold water with similar colors using a gentle cycle
2. Ironing: If ironing is necessary, iron inside-out on the lowest setting
3. Drying: Tumble dry low or hang-dry
4. No-Nos: Avoid using bleach and do not dry clean.
SHIPPING INFORMATION OF "S Release The Mueller Report T Shirt 4889"
The "S Release The Mueller Report T Shirt 4889" shirt is printed in United States and United Kingdom.
It normally takes us few days for printing the shirt and 5 - 8 business days for delivery.
The tracking information will be updated right after the shirt is shipped.
Please note that it may take longer during holiday seasons.
Size: S,M,L,XL,2XL,3XL,4XL,5XL, Youth S, Youth M, Youth L, Youth XL
Color: Black, White, Sport Grey, Navy, Royal blue, Yellow, Light Pink, Red, Irish Green, Purple, Charcoal, Orange, Maroon, Forest Green, Light Blue
Some products we provide: Men Short Sleeve, Women Short Sleeve, Unisex Pullover Hoodie, Crew Neck Sweater, Long Sleeve T-shirt, Men V-neck, Women V-neck, Tank Top
Return policy: Every purchase comes with a 100% satisfaction guarantee! Have a problem? Send us an email and we will resolve your issue within 12-24 hours.


text:
Our Best Buy Here Pay Here Gassville Car Lot Dealers
DPD Auto Sales5 rated based on 6 reviews Get Approval Contact
Gassville, Baxter County
421 E Main St, Gassville, AR 72635, USA
Best Buy here pay here Gassville dealership
Are you looking for Car Dealerships With Buy Here Pay Here in Gassville? We have listed best buy here pay here car dealers in Gassville. These Buy Here Pay Here Car Dealers in Gassville sell cheap & used cars to customers with bad or no credit. You can sometimes even buy cars with low or no down payments. We have 1 dealers listed here at buy here pay here Gassville. We have compiled the list of best buy here pay here car lots dealers in Gassville and sorted them based on reviews, location, timings and few other factors like inventory etc.
We at bhphnearme.org are always here to help you get the used car of your dreams at cheap price. We make it easy and fast for used cars buyers to search for the nearest buy here pay here Gassville dealers that they can access. We offers a list of best BHPH Gassville dealers which you can access with complete contact details to give you more time to decide on which car to buy!
We have information on the nearest used cars for sale and special finance, no matter where you are in the United States. Our goal is to bring car buyers with a challenged credit score a step closer to their dreams.
Buy here pay here dealers in Gassville reviews.
We scored buy here pay here Gassville dealers on more than 25 variables across five categories, and analysed the results to give you a hand-picked list of the best buy here pay here delers in Gassville. There are 1 dealers listed above and sorted based on our review machanism. So, select one near you and contact them. bhphnearme.org wishing you a happy buying.
Buy here pay here Gassville no down payment dealerships
Do you want to buy a vehicle in Gassville? BUT you have bad credit or no credit? NO PROBLEM! Here we have 1 buy here pay here Gassville dealers from where you can buy used cars at cheap price. Choose from 1 BHPH dealers in Gassville and contact them with proof of income, proof of address, ID & your down payment. Once you find your Buy here pay here Gassville no down payment dealerships, explore there inventory and choose your perfect vehicle. You'll be driving away in your new vehicle in less than one hour!
Buy here pay here Gassville FAQs
1. What Does "Buy Here Pay Here Gassville" Mean?
Buy here pay here in automobile is business modal for dealers in which dealers themselves extend credit to purchasers who have poor credit history, and loans have high interest rates.
2. How to find Buy Here Pay Here Dealer in Gassville?
At bhphnearme.org you can find best BHPH dealers in Gassville sorted by reviews from real users.
3. Who Should Go To a BHPH Gassville Dealership?
If you are a first time buyer, have low or bad credit, or if you have had trouble getting an auto loan, a BHPH dealership should be one of the places you visit during a car search.
4. How big a down payment do I need?
That depends on the price of the car and your existing credit score. A more significant down payment will always improve your chances of obtaining approval sooner.
5. Can I get approved with bad credit?
Yes, that's our specialty! RightWay dealerships are truly the auto credit experts and help customers with bad credit drive away in nicer, newer vehicles every day.


text: Vancouver Canada Boating Boat Photographer Marine, Exterior, Boating, Yacht, Mega Yacht,Pontoon, Fishing Boat and Sailing Photography by Denver Colorado based Commercial Advertising Photographer Richard Steinberger. Also available for assignments in Florida, Washington, California, Minnesota, Wisconsin, Indiana, Tennessee and worldwide. Photographer for such international brands as Sea Ray Yachts, Meridian Yachts, Boston Whaler Fishing Boats, and Bayliner Boats.


text:
You know you're a breadmaker when.....
Just for fun, finish the sentence:
You know you're a true breadmaker when...
.... you time your morning run around your bread rising.
.... you have an entire shelf of your pantry devoted to flours.
.... you think making a 4 hour yeasted bread instead of using your starter is "cheating".
.... you consider store bought, sliced white bread to be a freak of nature.
..... you own, or have borrowed from the library, every single one of the bread books advertised on this site.


text:
We welcome new information from any source about the exonerations
that are already on our list and about new cases that might
be exonerations. And we will be happy to respond to inquiries
about the Registry.
The National Registry of Exonerations is a project of
the University of Michigan Law School
Follow Us:


text:
Pacific Island Ecosystems at Risk (PIER)
PIER reference
Bishop Museum (Honolulu). 1968. Voucher specimen #BISH 28703 (Bristol, M.L. 2170)
Need more info? Have questions? Comments? Information to contribute?
Contact PIER! (firstname.lastname@example.com)
PIER home
The template for this page was created on 27 May 2005; it was last modified on 27 September 2005 by
. The page content was last refreshed on 26 Feb 2019.


text:
CRM Development in company Latvia
Redian Software is a leading CRM development and implementation company. Our expertise on open source CRMs like SuiteCRM, SugarCRM and vTiger along with cloud-based CRM like Zoho, Salesforce give a wide range to our customers to choose from.
We have implemented CRMs for across industries such as healthcare, pharmaceuticals, Manufacturing, Travel, Hospitality, Aviation, Education, Insurance, Finance, Banking, Media, Entertainment, Retail, e-Commerce for clients across the world.
How Redian Software helps business in CRM adaption
Our purpose is to transform the legacy systems and making the whole process effective with use of CRM. And our core objectives are to:
- Increase the efficiency of the business process
- Manage the workload and automate the business
- Continuous improvement and optimization
- Remove the redundancies
CRM Solutions & offerings by Redian Software
SuiteCRM implementation
SuiteCRM is a leading open source CRM and adopted by a wide range of customers across the world. It was forked from the SugarCRM and is based on PHP, MySQL. We offer a wide range of SuiteCRM customization and integration services for customers across the industries.
SugarCRM Implementation
SugarCRM is another open-source CRM and used by large and medium enterprises. It is also known as the parent of SuiteCRM. Redian Software has customized and implemented SuiteCRM for various clients and integrated with 3rd party applications to match the business requirements.
Zoho Implementation
A powerful cloud-based CRM platform accepted by more than 150000 businesses across the world. Zoho is a complete Suite for any business and offers more than 40 applications ranging from sales and marketing to HR and people management, finance to procurement and IT & HelpDesk. We offer end to end Zoho implementation services for across the industries.
Salesforce Implementation
Salesforce is another powerful cloud-based CRM trusted by millions of customers across the world by enterprises. It has been one of the most reliable CRM platforms and offers various features to transform businesses. We, at Redian Software offers end to end implementation services of Salesforce CRM for different industries by our team of salesforce professionals.


text:
Difference between revisions of "IO inside"
|Line 1,154:
|Line 1,154:
A little disclaimer: I should say that I'm not describing
A little disclaimer: I should say that I'm not describing
here exactly what a monad is (I don't even completely understand it myself) and my explanation shows only one _possible_ way to implement the IO monad in
here exactly what a monad is (I don't even completely understand it myself) and my explanation shows only one _possible_ way to implement the IO monad in
Haskell. For example, the hbc Haskell compiler implements
Haskell. For example, the hbc Haskell compiler implements via
continuations. I also haven't said anything about exception handling,
continuations. I also haven't said anything about exception handling,
which is a natural part of the "monad" concept. You can read the "All About
which is a natural part of the "monad" concept. You can read the "All About
Monads" guide to learn more about these topics.
Monads" guide to learn more about these topics.
But there is some good news: first, the monad understanding you've just acquired will work with any implementation. You just can't work with RealWorld
But there is some good news: first, the monad understanding you've just acquired will work with any implementation. You just can't work with RealWorld
values directly.
values directly.
Revision as of 12:11, 6 September 2007
Haskell I/O has always been a source of confusion and surprises for new Haskellers. While simple I/O code in Haskell looks very similar to its equivalents in imperative languages, attempts to write somewhat more complex code often result in a total mess. This is because Haskell I/O is really very different internally. Haskell is a pure language and even the I/O system can't break this purity.
The following text is an attempt to explain the details of Haskell I/O implementations. This explanation should help you eventually master all the smart I/O tricks. Moreover, I've added a detailed explanation of various traps you might encounter along the way. After reading this text, you will receive a "Master of Haskell I/O" degree that is equal to a Bachelor in Computer Science and Mathematics, simultaneously :)
If you are new to Haskell I/O you may prefer to start by reading the Introduction to IO page.
Haskell is a pure language
Haskell is a pure language, which means that the result of any function call is fully determined by its arguments. Pseudo-functions like rand() or getchar() in C, which return different results on each call, are simply impossible to write in Haskell. Moreover, Haskell functions can't have side effects, which means that they can't effect any changes to the "real world", like changing files, writing to the screen, printing, sending data over the network, and so on. These two restrictions together mean that any function call can be omitted, repeated, or replaced by the result of a previous call with the same parameters, and the language guarantees that all these rearrangements will not change the program result!
Let's compare this to C: optimizing C compilers try to guess which functions have no side effects and don't depend on mutable global variables. If this guess is wrong, an optimization can change the program's semantics! To avoid this kind of disaster, C optimizers are conservative in their guesses or require hints from the programmer about the purity of functions.
Compared to an optimizing C compiler, a Haskell compiler is a set of pure mathematical transformations. This results in much better high-level optimization facilities. Moreover, pure mathematical computations can be much more easily divided into several threads that may be executed in parallel, which is increasingly important in these days of multi-core CPUs. Finally, pure computations are less error-prone and easier to verify, which adds to Haskell's robustness and to the speed of program development using Haskell.
Haskell purity allows compiler to call only functions whose results
are really required to calculate final value of high-level function
(i.e., main) - this is called lazy evaluation. It's great thing for
pure mathematical computations, but how about I/O actions? Function
like (
putStrLn "Press any key to begin formatting") can't return any
meaningful result value, so how can we ensure that compiler will not
omit or reorder its execution? And in general: how we can work with
stateful algorithms and side effects in an entirely lazy language?
This question has had many different solutions proposed in 18 years of
Haskell development (see History of Haskell), though a solution based on monads is now
the standard.
What is a monad?
What is a monad? It's something from mathematical category theory, which I don't know anymore :) In order to understand how monads are used to solve the problem of I/O and side effects, you don't need to know it. It's enough to just know elementary mathematics, like I do :)
Let's imagine that we want to implement in Haskell the well-known 'getchar' function. What type should it have? Let's try:
getchar :: Char
get2chars = [getchar,getchar]
What will we get with 'getchar' having just the 'Char' type? You can see all the possible problems in the definition of 'get2chars':
- Because the Haskell compiler treats all functions as pure (not having side effects), it can avoid "excessive" calls to 'getchar' and use one returned value twice.
- Even if it does make two calls, there is no way to determine which call should be performed first. Do you want to return the two chars in the order in which they were read, or in the opposite order? Nothing in the definition of 'get2chars' answers this question.
How can these problems be solved, from the programmer's viewpoint? Let's introduce a fake parameter of 'getchar' to make each call "different" from the compiler's point of view:
getchar :: Int -> Char
get2chars = [getchar 1, getchar 2]
Right away, this solves the first problem mentioned above - now the compiler will make two calls because it sees them as having different parameters. The whole 'get2chars' function should also have a fake parameter, otherwise we will have the same problem calling it:
getchar :: Int -> Char
get2chars :: Int -> String
get2chars _ = [getchar 1, getchar 2]
Now we need to give the compiler some clue to determine which function it should call first. The Haskell language doesn't provide any way to express order of evaluation... except for data dependencies! How about adding an artificial data dependency which prevents evaluation of the second 'getchar' before the first one? In order to achieve this, we will return an additional fake result from 'getchar' that will be used as a parameter for the next 'getchar' call:
getchar :: Int -> (Char, Int)
get2chars _ = [a,b] where (a,i) = getchar 1
(b,_) = getchar i
So far so good - now we can guarantee that 'a' is read before 'b' because reading 'b' needs the value ('i') that is returned by reading 'a'!
We've added a fake parameter to 'get2chars' but the problem is that the Haskell compiler is too smart! It can believe that the external 'getchar' function is really dependent on its parameter but for 'get2chars' it will see that we're just cheating because we throw it away! Therefore it won't feel obliged to execute the calls in the order we want. How can we fix this? How about passing this fake parameter to the 'getchar' function?! In this case the compiler can't guess that it is really unused :)
get2chars i0 = [a,b] where (a,i1) = getchar i0
(b,i2) = getchar i1
And more - 'get2chars' has all the same purity problems as the 'getchar' function. If you need to call it two times, you need a way to describe the order of these calls. Look at:
get4chars = [get2chars 1, get2chars 2] -- order of 'get2chars' calls isn't defined
We already know how to deal with these problems - 'get2chars' should also return some fake value that can be used to order calls:
get2chars :: Int -> (String, Int)
get4chars i0 = (a++b) where (a,i1) = get2chars i0
(b,i2) = get2chars i1
But what's the fake value 'get2chars' should return? If we use some integer constant, the excessively-smart Haskell compiler will guess that we're cheating again :) What about returning the value returned by 'getchar'? See:
get2chars :: Int -> (String, Int)
get2chars i0 = ([a,b], i2) where (a,i1) = getchar i0
(b,i2) = getchar i1
Believe it or not, but we've just constructed the whole "monadic" Haskell I/O system.
Welcome to the RealWorld, baby :)
The 'main' Haskell function has the type:
main :: RealWorld -> ((), RealWorld)
where 'RealWorld' is a fake type used instead of our Int. It's something like the baton passed in a relay race. When 'main' calls some IO function, it passes the "RealWorld" it received as a parameter. All IO functions have similar types involving RealWorld as a parameter and result. To be exact, "IO" is a type synonym defined in the following way:
type IO a = RealWorld -> (a, RealWorld)
So, 'main' just has type "IO ()", 'getChar' has type "IO Char" and so on. You can think of the type "IO Char" as meaning "take the current RealWorld, do something to it, and return a Char and a (possibly changed) RealWorld". Let's look at 'main' calling 'getChar' two times:
getChar :: RealWorld -> (Char, RealWorld)
main :: RealWorld -> ((), RealWorld)
main world0 = let (a, world1) = getChar world0
(b, world2) = getChar world1
in ((), world2)
Look at this closely: 'main' passes to first 'getChar' the "world" it received. This 'getChar' returns some new value of type RealWorld that gets used in the next call. Finally, 'main' returns the "world" it got from the second 'getChar'.
- Is it possible here to omit any call of 'getChar' if the Char it read is not used? No, because we need to return the "world" that is the result of the second 'getChar' and this in turn requires the "world" returned from the first 'getChar'.
- Is it possible to reorder the 'getChar' calls? No: the second 'getChar' can't be called before the first one because it uses the "world" returned from the first call.
- Is it possible to duplicate calls? In Haskell semantics - yes, but real compilers never duplicate work in such simple cases (otherwise, the programs generated will not have any speed guarantees).
As we already said, RealWorld values are used like a baton which gets passed between all routines called by 'main' in strict order. Inside each routine called, RealWorld values are used in the same way. Overall, in order to "compute" the world to be returned from 'main', we should perform each IO procedure that is called from 'main', directly or indirectly. This means that each procedure inserted in the chain will be performed just at the moment (relative to the other IO actions) when we intended it to be called. Let's consider the following program:
main = do a <- ask "What is your name?"
b <- ask "How old are you?"
return ()
ask s = do putStr s
Now you have enough knowledge to rewrite it in a low-level way and check that each operation that should be performed will really be performed with the arguments it should have and in the order we expect.
But what about conditional execution? No problem. Let's define the well-known 'when' operation:
when :: Bool -> IO () -> IO ()
when condition action world =
if condition
then action world
else ((), world)
As you can see, we can easily include or exclude from the execution chain IO procedures (actions) depending on the data values. If 'condition' will be False on the call of 'when', 'action' will never be called because real Haskell compilers, again, never call functions whose results are not required to calculate the final result (i.e., here, the final "world" value of 'main').
Loops and more complex control structures can be implemented in the same way. Try it as an exercise!
Finally, you may want to know how much passing these RealWorld values around the program costs. It's free! These fake values exist solely for the compiler while it analyzes and optimizes the code, but when it gets to assembly code generation, it "suddenly" realize that this type is like "()", so all these parameters and result values can be omitted from the final generated code. Isn't it beautiful? :)
'>>=' and 'do' notation
All beginners (including me :)) start by thinking that 'do' is some magic statement that executes IO actions. That's wrong - 'do' is just syntactic sugar that simplifies the writing of procedures that use IO (and also other monads, but that's beyond the scope of this tutorial). 'do' notation eventually gets translated to statements passing "world" values around like we've manually written above and is used to simplify the gluing of several IO actions together. You don't need to use 'do' for just one statement; for instance,
main = do putStr "Hello!"
is desugared to:
main = putStr "Hello!"
But nevertheless it's considered Good Style to use 'do' even for one statement because it simplifies adding new statements in the future.
Let's examine how to desugar a 'do' with multiple statements in the following example:
main = do putStr "What is your name?"
putStr "How old are you?"
putStr "Nice day!"
The 'do' statement here just joins several IO actions that should be performed sequentially. It's translated to sequential applications of one of the so-called "binding operators", namely '>>':
main = (putStr "What is your name?")
>> ( (putStr "How old are you?")
>> (putStr "Nice day!")
This binding operator just combines two IO actions, executing them sequentially by passing the "world" between them:
(>>) :: IO a -> IO b -> IO b
(action1 >> action2) world0 =
let (a, world1) = action1 world0
(b, world2) = action2 world1
in (b, world2)
If defining operators this way looks strange to you, read this definition as follows:
action1 >> action2 = action
action world0 = let (a, world1) = action1 world0
(b, world2) = action2 world1
in (b, world2)
Now you can substitute the definition of '>>' at the places of its usage and check that program constructed by the 'do' desugaring is actually the same as we could write by manually manipulating "world" values.
A more complex example involves the binding of variables using "<-":
main = do a <- readLn
print a
This code is desugared into:
main = readLn
>>= (\a -> print a)
As you should remember, the '>>' binding operator silently ignores the value of its first action and returns as an overall result the result of its second action only. On the other hand, the '>>=' binding operator (note the extra '=' at the end) allows us to use the result of its first action - it gets passed as an additional parameter to the second one! Look at the definition:
(>>=) :: IO a -> (a -> IO b) -> IO b
(action1 >>= action2) world0 =
let (a, world1) = action1 world0
(b, world2) = action2 a world1
in (b, world2)
First, what does the type of the second "action" (more precisely, a function which returns an IO action), namely "a -> IO b", mean? By substituting the "IO" definition, we get "a -> RealWorld -> (b, RealWorld)". This means that second action actually has two parameters - the type 'a' actually used inside it, and the value of type RealWorld used for sequencing of IO actions. That's always the case - any IO procedure has one more parameter compared to what you see in its type signature. This parameter is hidden inside the definition of the type alias "IO".
Second, you can use these '>>' and '>>=' operations to simplify your program. For example, in the code above we don't need to introduce the variable, because the result of 'readLn' can be send directly to 'print':
main = readLn >>= print
And third - as you see, the notation:
do x <- action1
where 'action1' has type "IO a" and 'action2' has type "IO b", translates into:
action1 >>= (\x -> action2)
where the second argument of '>>=' has the type "a -> IO b". It's the way the '<-' binding is processed - the name on the left-hand side of '<-' just becomes a parameter of subsequent operations represented as one large IO action. Note also that if 'action1' has type "IO a" then 'x' will just have type "a"; you can think of the effect of '<-' as "unpacking" the IO value of 'action1' into 'x'. Note also that '<-' is not a true operator; it's pure syntax, just like 'do' itself. Its meaning results only from the way it gets desugared.
Look at the next example:
main = do putStr "What is your name?"
a <- readLn
putStr "How old are you?"
b <- readLn
print (a,b)
This code is desugared into:
main = putStr "What is your name?"
>> readLn
>>= \a -> putStr "How old are you?"
>> readLn
>>= \b -> print (a,b)
I omitted the parentheses here; both the '>>' and the '>>=' operators are left-associative, but lambda-bindings always stretches as far to the right as possible, which means that the 'a' and 'b' bindings introduced here are valid for all remaining actions. As an exercise, add the parentheses yourself and translate this procedure into the low-level code that explicitly passes "world" values. I think it should be enough to help you finally realize how the 'do' translation and binding operators work.
Oh, no! I forgot the third monadic operator - 'return'. It just combines its two parameters - the value passed and "world":
return :: a -> IO a
return a world0 = (a, world0)
How about translating a simple example of 'return' usage? Say,
main = do a <- readLn
return (a*2)
Programmers with an imperative language background often think that 'return' in Haskell, as in other languages, immediately returns from the IO procedure. As you can see in its definition (and even just from its type!), such an assumption is totally wrong. The only purpose of using 'return' is to "lift" some value (of type 'a') into the result of a whole action (of type "IO a") and therefore it should generally be used only as the last executed statement of some IO sequence. For example try to translate the following procedure into the corresponding low-level code:
main = do a <- readLn
when (a>=0) $ do
return ()
print "a is negative"
and you will realize that the 'print' statement is executed even for non-negative values of 'a'. If you need to escape from the middle of an IO procedure, you can use the 'if' statement:
main = do a <- readLn
if (a>=0)
then return ()
else print "a is negative"
Moreover, Haskell layout rules allow us to use the following layout:
main = do a <- readLn
if (a>=0) then return ()
else do
print "a is negative"
that may be useful for escaping from the middle of a longish 'do' statement.
Last exercise: implement a function 'liftM' that lifts operations on plain values to the operations on monadic ones. Its type signature:
liftM :: (a -> b) -> (IO a -> IO b)
If that's too hard for you, start with the following high-level definition and rewrite it in low-level fashion:
liftM f action = do x <- action
return (f x)
Mutable data (references, arrays, hash tables...)
As you should know, every name in Haskell is bound to one fixed (immutable) value. This greatly simplifies understanding algorithms and code optimization, but it's inappropriate in some cases. As we all know, there are plenty of algorithms that are simpler to implement in terms of updatable variables, arrays and so on. This means that the value associated with a variable, for example, can be different at different execution points, so reading its value can't be considered as a pure function. Imagine, for example, the following code:
main = do let a0 = readVariable varA
_ = writeVariable varA 1
a1 = readVariable varA
print (a0, a1)
Does this look strange? First, the two calls to 'readVariable' look the same, so the compiler can just reuse the value returned by the first call. Second, the result of the 'writeVariable' call isn't used so the compiler can (and will!) omit this call completely. To complete the picture, these three calls may be rearranged in any order because they appear to be independent of each other. This is obviously not what was intended. What's the solution? You already know this - use IO actions! Using IO actions guarantees that:
- the execution order will be retained as written
- each action will have to be executed
- the result of the "same" action (such as "readVariable varA") will not be reused
So, the code above really should be written as:
main = do varA <- newIORef 0 -- Create and initialize a new variable
a0 <- readIORef varA
writeIORef varA 1
a1 <- readIORef varA
print (a0, a1)
Here, 'varA' has the type "IORef Int" which means "a variable (reference) in the IO monad holding a value of type Int". newIORef creates a new variable (reference) and returns it, and then read/write actions use this reference. The value returned by the "readIORef varA" action depends not only on the variable involved but also on the moment this operation is performed so it can return different values on each call.
Arrays, hash tables and any other _mutable_ data structures are defined in the same way - for each of them, there's an operation that creates new "mutable values" and returns a reference to it. Then special read and write operations in the IO monad are used. The following code shows an example using mutable arrays:
import Data.Array.IO
main = do arr <- newArray (1,10) 37 :: IO (IOArray Int Int)
a <- readArray arr 1
writeArray arr 1 64
b <- readArray arr 1
print (a, b)
Here, an array of 10 elements with 37 as the initial value at each location is created. After reading the value of the first element (index 1) into 'a' this element's value is changed to 64 and then read again into 'b'. As you can see by executing this code, 'a' will be set to 37 and 'b' to 64.
Other state-dependent operations are also often implemented as IO actions. For example, a random number generator should return a different value on each call. It looks natural to give it a type involving IO:
rand :: IO Int
Moreover, when you import C routines you should be careful - if this routine is impure, i.e. its result depends on something in the "real world" (file system, memory contents...), internal state and so on, you should give it an IO type. Otherwise, the compiler can "optimize" repetitive calls of this procedure with the same parameters! :)
For example, we can write a non-IO type for:
foreign import ccall
sin :: Double -> Double
because the result of 'sin' depends only on its argument, but
foreign import ccall
tell :: Int -> IO Int
If you will declare 'tell' as a pure function (without IO) then you may get the same position on each call! :)
IO actions as values
By this point you should understand why it's impossible to use IO actions inside non-IO (pure) procedures. Such procedures just don't get a "baton"; they don't know any "world" value to pass to an IO action. The RealWorld type is an abstract datatype, so pure functions also can't construct RealWorld values by themselves, and it's a strict type, so 'undefined' also can't be used. So, the prohibition of using IO actions inside pure procedures is just a type system trick (as it usually is in Haskell :)).
But while pure code can't _execute_ IO actions, it can work with them as with any other functional values - they can be stored in data structures, passed as parameters, returned as results, collected in lists, and partially applied. But an IO action will remain a functional value because we can't apply it to the last argument - of type RealWorld.
In order to _execute_ the IO action we need to apply it to some RealWorld value. That can be done only inside some IO procedure, in its "actions chain". And real execution of this action will take place only when this procedure is called as part of the process of "calculating the final value of world" for 'main'. Look at this example:
main world0 = let get2chars = getChar >> getChar
((), world1) = putStr "Press two keys" world0
(answer, world2) = get2chars world1
in ((), world2)
Here we first bind a value to 'get2chars' and then write a binding involving 'putStr'. But what's the execution order? It's not defined by the order of the 'let' bindings, it's defined by the order of processing "world" values! You can arbitrarily reorder the binding statements - the execution order will be defined by the data dependency with respect to the "world" values that get passed around. Let's see what this 'main' looks like in the 'do' notation:
main = do let get2chars = getChar >> getChar
putStr "Press two keys"
return ()
As you can see, we've eliminated two of the 'let' bindings and left only the one defining 'get2chars'. The non-'let' statements are executed in the exact order in which they're written, because they pass the "world" value from statement to statement as we described above. Thus, this version of the function is much easier to understand because we don't have to mentally figure out the data dependency of the "world" value.
Moreover, IO actions like 'get2chars' can't be executed directly because they are functions with a RealWorld parameter. To execute them, we need to supply the RealWorld parameter, i.e. insert them in the 'main' chain, placing them in some 'do' sequence executed from 'main' (either directly in the 'main' function, or indirectly in an IO function called from 'main'). Until that's done, they will remain like any function, in partially evaluated form. And we can work with IO actions as with any other functions - bind them to names (as we did above), save them in data structures, pass them as function parameters and return them as results - and they won't be performed until you give them the magic RealWorld parameter!
Example: a list of IO actions
Let's try defining a list of IO actions:
ioActions :: [IO ()]
ioActions = [(print "Hello!"),
(putStr "just kidding"),
(getChar >> return ())
I used additional parentheses around each action, although they aren't really required. If you still can't believe that these actions won't be executed immediately, just recall the real type of this list:
ioActions :: [RealWorld -> ((), RealWorld)]
Well, now we want to execute some of these actions. No problem, just insert them into the 'main' chain:
main = do head ioActions
ioActions !! 1
last ioActions
Looks strange, right? :) Really, any IO action that you write in a 'do' statement (or use as a parameter for the '>>'/'>>=' operators) is an expression returning a result of type 'IO a' for some type 'a'. Typically, you use some function that has the type 'x -> y -> ... -> IO a' and provide all the x, y, etc. parameters. But you're not limited to this standard scenario - don't forget that Haskell is a functional language and you're free to compute the functional value required (recall that "IO a" is really a function type) in any possible way. Here we just extracted several functions from the list - no problem. This functional value can also be constructed on-the-fly, as we've done in the previous example - that's also OK. Want to see this functional value passed as a parameter? Just look at the definition of 'when'. Hey, we can buy, sell, and rent these IO actions just like we can with any other functional values! For example, let's define a function that executes all the IO actions in the list:
sequence_ :: [IO a] -> IO ()
sequence_ [] = return ()
sequence_ (x:xs) = do x
sequence_ xs
No black magic - we just extract IO actions from the list and insert them into a chain of IO operations that should be performed one after another (in the same order that they occurred in the list) to "compute the final world value" of the entire 'sequence_' call.
With the help of 'sequence_', we can rewrite our last 'main' function as:
main = sequence_ ioActions
Haskell's ability to work with IO actions as with any other (functional and non-functional) values allows us to define control structures of arbitrary complexity. Try, for example, to define a control structure that repeats an action until it returns the 'False' result:
while :: IO Bool -> IO ()
while action = ???
Most programming languages don't allow you to define control structures at all, and those that do often require you to use a macro-expansion system. In Haskell, control structures are just trivial functions anyone can write.
Example: returning an IO action as a result
How about returning an IO action as the result of a function? Well, we've done this each time we've defined an IO procedure - they all return IO actions that need a RealWorld value to be performed. While we usually just execute them as part of a higher-level IO procedure, it's also possible to just collect them without actual execution:
main = do let a = sequence ioActions
b = when True getChar
c = getChar >> getChar
putStr "These 'let' statements are not executed!"
These assigned IO procedures can be used as parameters to other procedures, or written to global variables, or processed in some other way, or just executed later, as we did in the example with 'get2chars'.
But how about returning a parameterized IO action from an IO procedure? Let's define a procedure that returns the i'th byte from a file represented as a Handle:
readi h i = do hSeek h i AbsoluteSeek
hGetChar h
So far so good. But how about a procedure that returns the i'th byte of a file with a given name without reopening it each time?
readfilei :: String -> IO (Integer -> IO Char)
readfilei name = do h <- openFile name ReadMode
return (readi h)
As you can see, it's an IO procedure that opens a file and returns... another IO procedure that will read the specified byte. But we can go further and include the 'readi' body in 'readfilei':
readfilei name = do h <- openFile name ReadMode
let readi h i = do hSeek h i AbsoluteSeek
hGetChar h
return (readi h)
That's a little better. But why do we add 'h' as a parameter to 'readi' if it can be obtained from the environment where 'readi' is now defined? An even shorter version is this:
readfilei name = do h <- openFile name ReadMode
let readi i = do hSeek h i AbsoluteSeek
hGetChar h
return readi
What have we done here? We've build a parameterized IO action involving local names inside 'readfilei' and returned it as the result. Now it can be used in the following way:
main = do myfile <- readfilei "test"
a <- myfile 0
b <- myfile 1
print (a,b)
This way of using IO actions is very typical for Haskell programs - you just construct one or more IO actions that you need, with or without parameters, possibly involving the parameters that your "constructor" received, and return them to the caller. Then these IO actions can be used in the rest of the program without any knowledge about your internal implementation strategy. One thing this can be used for is to partially emulate the OOP (or more precisely, the ADT) programming paradigm.
Example: a memory allocator generator
As an example, one of my programs has a module which is a memory suballocator. It receives the address and size of a large memory block and returns two procedures - one to allocate a subblock of a given size and the other to free the allocated subblock:
memoryAllocator :: Ptr a -> Int -> IO (Int -> IO (Ptr b),
Ptr c -> IO ())
memoryAllocator buf size = do ......
let alloc size = do ...
free ptr = do ...
return (alloc, free)
How this is implemented? 'alloc' and 'free' work with references created inside the memoryAllocator procedure. Because the creation of these references is a part of the memoryAllocator IO actions chain, a new independent set of references will be created for each memory block for which memoryAllocator is called:
memoryAllocator buf size = do start <- newIORef buf
end <- newIORef (buf `plusPtr` size)
These two references are read and written in the 'alloc' and 'free' definitions (we'll implement a very simple memory allocator for this example):
let alloc size = do addr <- readIORef start
writeIORef start (addr `plusPtr` size)
return addr
let free ptr = do writeIORef start ptr
What we've defined here is just a pair of closures that use state available at the moment of their definition. As you can see, it's as easy as in any other functional language, despite Haskell's lack of direct support for impure functions.
The following example uses procedures, returned by memoryAllocator, to simultaneously allocate/free blocks in two independent memory buffers:
main = do buf1 <- mallocBytes (2^16)
buf2 <- mallocBytes (2^20)
(alloc1, free1) <- memoryAllocator buf1 (2^16)
(alloc2, free2) <- memoryAllocator buf2 (2^20)
ptr11 <- alloc1 100
ptr21 <- alloc2 1000
free1 ptr11
free2 ptr21
ptr12 <- alloc1 100
ptr22 <- alloc2 1000
Example: emulating OOP with record types
Let's implement the classical OOP example: drawing figures. There are figures of different types: circles, rectangles and so on. The task is to create a heterogeneous list of figures. All figures in this list should support the same set of operations: draw, move and so on. We will represent these operations as IO procedures. Instead of a "class" let's define a structure containing implementations of all the procedures required:
data Figure = Figure { draw :: IO (),
move :: Displacement -> IO ()
type Displacement = (Int, Int) -- horizontal and vertical displacement in points
The constructor of each figure's type should just return a Figure record:
circle :: Point -> Radius -> IO Figure
rectangle :: Point -> Point -> IO Figure
type Point = (Int, Int) -- point coordinates
type Radius = Int -- circle radius in points
We will "draw" figures by just printing their current parameters. Let's start with a simplified implementation of the 'circle' and 'rectangle' constructors, without actual 'move' support:
circle center radius = do
let description = " Circle at "++show center++" with radius "++show radius
return $ Figure { draw = putStrLn description }
rectangle from to = do
let description = " Rectangle "++show from++"-"++show to)
return $ Figure { draw = putStrLn description }
As you see, each constructor just returns a fixed 'draw' procedure that prints parameters with which the concrete figure was created. Let's test it:
drawAll :: [Figure] -> IO ()
drawAll figures = do putStrLn "Drawing figures:"
mapM_ draw figures
main = do figures <- sequence [circle (10,10) 5,
circle (20,20) 3,
rectangle (10,10) (20,20),
rectangle (15,15) (40,40)]
drawAll figures
Now let's define "full-featured" figures that can actually be moved around. In order to achieve this, we should provide each figure with a mutable variable that holds each figure's current screen location. The type of this variable will be "IORef Point". This variable should be created in the figure constructor and manipulated in IO procedures (closures) enclosed in the Figure record:
circle center radius = do
centerVar <- newIORef center
let drawF = do center <- readIORef centerVar
putStrLn (" Circle at "++show center
++" with radius "++show radius)
let moveF (addX,addY) = do (x,y) <- readIORef centerVar
writeIORef centerVar (x+addX, y+addY)
return $ Figure { draw=drawF, move=moveF }
rectangle from to = do
fromVar <- newIORef from
toVar <- newIORef to
let drawF = do from <- readIORef fromVar
to <- readIORef toVar
putStrLn (" Rectangle "++show from++"-"++show to)
let moveF (addX,addY) = do (fromX,fromY) <- readIORef fromVar
(toX,toY) <- readIORef toVar
writeIORef fromVar (fromX+addX, fromY+addY)
writeIORef toVar (toX+addX, toY+addY)
return $ Figure { draw=drawF, move=moveF }
Now we can test the code which moves figures around:
main = do figures <- sequence [circle (10,10) 5,
rectangle (10,10) (20,20)]
drawAll figures
mapM_ (\fig -> move fig (10,10)) figures
drawAll figures
It's important to realize that we are not limited to including only IO actions in a record that's intended to simulate a C++/Java-style interface. The record can also include values, IORefs, pure functions - in short, any type of data. For example, we can easily add to the Figure interface fields for area and origin:
data Figure = Figure { draw :: IO (),
move :: Displacement -> IO (),
area :: Double,
origin :: IORef Point
Dark side of IO monad
Programmers coming from an imperative language background often look for a way to execute IO actions inside a pure procedure. But what does this mean? Imagine that you're trying to write a procedure that reads the contents of a file with a given name, and you try to write it as a pure (non-IO) function:
readContents :: Filename -> String
Defining readContents as a pure function will certainly simplify the code that uses it. But it will also create problems for the compiler:
- This call is not inserted in a sequence of "world transformations", so the compiler doesn't know at what exact moment you want to execute this action. For example, if the file has one kind of contents at the beginning of the program and another at the end - which contents do you want to see? You have no idea when (or even if) this function is going to get invoked, because Haskell sees this function as pure and feels free to reorder the execution of any or all pure functions as needed.
- Attempts to read the contents of files with the same name can be factored (i.e. reduced to a single call) despite the fact that the file (or the current directory) can be changed between calls. Again, Haskell considers all non-IO functions to be pure and feels free to omit multiple calls with the same parameters.
So, implementing pure functions that interact with the Real World is considered to be Bad Behavior. Good boys and girls never do it ;)
Nevertheless, there are (semi-official) ways to use IO actions inside of pure functions. As you should remember this is prohibited by requiring the RealWorld "baton" in order to call an IO action. Pure functions don't have the baton, but there is a special "magic" procedure that produces this baton from nowhere, uses it to call an IO action and then throws the resulting "world" away! It's a little low-level magic :) This very special (and dangerous) procedure is:
unsafePerformIO :: IO a -> a
Let's look at its (possible) definition:
unsafePerformIO :: (RealWorld -> (a, RealWorld)) -> a
unsafePerformIO action = let (a, world1) = action createNewWorld
in a
where 'createNewWorld' is an internal function producing a new value of the RealWorld type.
Using unsafePerformIO, you can easily write pure functions that do I/O inside. But don't do this without a real need, and remember to follow this rule: the compiler doesn't know that you are cheating; it still considers each non-IO function to be a pure one. Therefore, all the usual optimization rules can (and will!) be applied to its execution. So you must ensure that:
- The result of each call depends only on its arguments.
- You don't rely on side-effects of this function, which may be not executed if its results are not needed.
Let's investigate this problem more deeply. Function evaluation in Haskell is determined by a value's necessity - the language computes only the values that are really required to calculate the final result. But what does this mean with respect to the 'main' function? To "calculate the final world's" value, you need to perform all the intermediate IO actions that are included in the 'main' chain. By using 'unsafePerformIO' we call IO actions outside of this chain. What guarantee do we have that they will be run at all? None. The only time they will be run is if running them is required to compute the overall function result (which in turn should be required to perform some action in the 'main' chain). This is an example of Haskell's evaluation-by-need strategy. Now you should clearly see the difference:
- An IO action inside an IO procedure is guaranteed to execute as long as it is (directly or indirectly) inside the 'main' chain - even when its result isn't used (because the implicit "world" value it returns will be used). You directly specify the order of the action's execution inside the IO procedure. Data dependencies are simulated via the implicit "world" values that are passed from each IO action to the next.
- An IO action inside 'unsafePerformIO' will be performed only if result of this operation is really used. The evaluation order is not guaranteed and you should not rely on it (except when you're sure about whatever data dependencies may exist).
I should also say that inside 'unsafePerformIO' call you can organize a small internal chain of IO actions with the help of the same binding operators and/or 'do' syntactic sugar we've seen above. For example, here's a particularly convoluted way to compute the integer that comes after zero:
one :: Int
one = unsafePerformIO $ do var <- newIORef 0
modifyIORef var (+1)
readIORef var
and in this case ALL the operations in this chain will be performed as long as the result of the 'unsafePerformIO' call is needed. To ensure this, the actual 'unsafePerformIO' implementation evaluates the "world" returned by the 'action':
unsafePerformIO action = let (a,world1) = action createNewWorld
in (world1 `seq` a)
(The 'seq' operation strictly evaluates its first argument before returning the value of the second one).
inlinePerformIO has the same definition as unsafePerformIO but with addition of INLINE pragma:
-- | Just like unsafePerformIO, but we inline it. Big performance gains as
-- it exposes lots of things to further inlining
{-# INLINE inlinePerformIO #-}
inlinePerformIO action = let (a, world1) = action createNewWorld
in (world1 `seq` a)
Semantically inlinePerformIO = unsafePerformIO in as much as either of those have any semantics at all.
The difference of course is that inlinePerformIO is even less safe than unsafePerformIO. While ghc will try not to duplicate or common up different uses of unsafePerformIO, we aggressively inline inlinePerformIO. So you can really only use it where the IO content is really properly pure, like reading from an immutable memory buffer (as in the case of ByteStrings). However things like allocating new buffers should not be done inside inlinePerformIO since that can easily be floated out and performed just once for the whole program, so you end up with many things sharing the same buffer, which would be bad.
So the rule of thumb is that IO things wrapped in unsafePerformIO have to be externally pure while with inlinePerformIO it has to be really really pure or it'll all go horribly wrong.
That said, here's some really hairy code. This should frighten any pure functional programmer...
write :: Int -> (Ptr Word8 -> IO ()) -> Put ()
write !n body = Put $ \c buf@(Buffer fp o u l) ->
if n <= l
then write' c fp o u l
else write' (flushOld c n fp o u) (newBuffer c n) 0 0 0
where {-# NOINLINE write' #-}
write' c !fp !o !u !l =
-- warning: this is a tad hardcore
(withForeignPtr fp
(\p -> body $! (p `plusPtr` (o+u))))
`seq` c () (Buffer fp o (u+n) (l-n))
it's used like:
word8 w = write 1 (\p -> poke p w)
This does not adhere to my rule of thumb above. Don't ask exactly why we claim it's safe :-) (and if anyone really wants to know, ask Ross Paterson who did it first in the Builder monoid)
But there is an even stranger operation called 'unsafeInterleaveIO' that gets the "official baton", makes its own pirate copy, and then runs an "illegal" relay-race in parallel with the main one! I can't talk further about its behavior without causing grief and indignation, so it's no surprise that this operation is widely used in countries that are hotbeds of software piracy such as Russia and China! ;) Don't even ask me - I won't say anything more about this dirty trick I use all the time ;)
One can use unsafePerformIO (not unsafeInterleaveIO) to perform I/O operations not in predefined order but by demand. For example, the following code:
do let c = unsafePerformIO getChar
do_proc c
will perform getChar I/O call only when value of c is really required by code, i.e. it this call will be performed lazily as any usual Haskell computation.
Now imagine the following code:
do let s = [unsafePerformIO getChar, unsafePerformIO getChar, unsafePerformIO getChar]
do_proc s
Three chars inside this list will be computed on demand too, and this means that their values will depend on the order they are consumed. It is not that we usually need :)
unsafeInterleaveIO solves this problem - it performs I/O only on demand but allows to define exact *internal* execution order for parts of your datastructure. It is why I wrote that unsafeInterleaveIO makes illegal copy of baton :)
First, unsafeInterleaveIO has (IO a) action as a parameter and returns value of type 'a':
do str <- unsafeInterleaveIO myGetContents
Second, unsafeInterleaveIO don't perform any action immediately, it only creates a box of type 'a' which on requesting this value will perform action specified as a parameter.
Third, this action by itself may compute the whole value immediately or... use unsafeInterleaveIO again to defer calculation of some sub-components:
myGetContents = do
c <- getChar
s <- unsafeInterleaveIO myGetContents
return (c:s)
This code will be executed only at the moment when value of str is really demanded. In this moment, getChar will be performed (with result assigned to c) and one more lazy IO box will be created - for s. This box again contains link to the myGetContents call
Then, list cell returned that contains one char read and link to myGetContents call as a way to compute rest of the list. Only at the moment when next value in list required, this operation will be performed again
As a final result, we get inability to read second char in list before first one, but lazy character of reading in whole. bingo!
PS: of course, actual code should include EOF checking. also note that you can read many chars/records at each call:
myGetContents = do
c <- replicateM 512 getChar
s <- unsafeInterleaveIO myGetContents
return (c++s)
Welcome to the machine: the actual GHC implementation
A little disclaimer: I should say that I'm not describing here exactly what a monad is (I don't even completely understand it myself) and my explanation shows only one _possible_ way to implement the IO monad in Haskell. For example, the hbc Haskell compiler implements IO monad via continuations. I also haven't said anything about exception handling, which is a natural part of the "monad" concept. You can read the "All About Monads" guide to learn more about these topics.
But there is some good news: first, the IO monad understanding you've just acquired will work with any implementation and with many other monads. You just can't work with RealWorld values directly.
Second, the IO monad implementation described here is really used in the GHC, yhc/nhc (Hugs/jhc, too?) compilers. Here is the actual IO definition from the GHC sources:
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
It uses the "State# RealWorld" type instead of our RealWorld, it uses the "(# #)" strict tuple for optimization, and it adds an IO data constructor around the type. Nevertheless, there are no significant changes from the standpoint of our explanation. Knowing the principle of "chaining" IO actions via fake "state of the world" values, you can now easily understand and write low-level implementations of GHC I/O operations.
The Yhc/nhc98 implementation
data World = World
newtype IO a = IO (World -> Either IOError a)
This implementation makes the "World" disappear somewhat, and returns Either a result of type "a", or if an error occurs then "IOError". The lack of the World on the right-hand side of the function can only be done because the compiler knows special things about the IO type, and won't overoptimise it.
Further reading
This tutorial is largely based on the Simon Peyton Jones' paper Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell. I hope that my tutorial improves his original explanation of the Haskell I/O system and brings it closer to the point of view of beginning Haskell programmers. But if you need to learn about concurrency, exceptions and FFI in Haskell/GHC, the original paper is the best source of information.
You can find more information about concurrency, FFI and STM at the GHC/Concurrency#Starting points page.
The Arrays page contains exhaustive explanations about using mutable arrays.
Look also at the Books and tutorials#Using Monads page, which contains tutorials and papers really describing these mysterious monads :)
An explanation of the basic monad functions, with examples, can be found in the reference guide A tour of the Haskell Monad functions, by Henk-Jan van Tuyl.
Do you have more questions? Ask in the haskell-cafe mailing list.
To-do list
If you are interested in adding more information to this manual, please add your questions/topics here.
- fixIO and 'mdo'
- ST monad
- Q monad
- split '>>='/'>>'/return section and 'do' section, more examples of using binding operators
- IORef detailed explanation (==const*), usage examples, syntax sugar, unboxed refs
- control structures developing - much more examples
- unsafePerformIO usage examples: global variable, ByteString, other examples
- actual GHC implementation - how to write low-level routines on example of newIORef implementation
This manual is collective work, so feel free to add more information to it yourself. The final goal is to collectively develop a comprehensive manual for using the IO monad.


text:
Company Info
Company Overview
References & Installations
User quotes
Choose your training solution
TouchConsoles for Sinapse Print Simulators
Why simulators are a good solution
Case studies
Product Demos
Product options
News and Events
A great, best practice tool that I'm sure you'll be interested in !
WorldSkills competition and Sinapse Print Simulators
Latest versions
What the press is saying
Partnership with Print Process Champions
Previous contests
Request trial versions
System Requirements
Installation and Downloads
Support Request Form
FAQ : Implemention in Industry
FAQ: Implementation in Graphic Arts Schools
Want us to call you ?
Where to find us
Global network
Job opportunities
Demonstration request
Request Trial Version
Rechercher :
USA : Forsyth Technical Community College subscribes to Shots e-simulator
Sinapse Print Simulators hosts the Cluster of printing, publishing houses and digital printing technologies for 2 days of exchange in Paris
France : Pagora initiates one month connection to Sheetfed simulator for a group of 25 students
The Netherlands : GOC now uses a pool of 23 licenses Shots, Heastet, Flexo, Gravure and Newspaper with cloud connection
Belgium : Grafoc migrates its pool of 12 licenses when renewing the support contract.
Russia : Rybinsk College installs a SHOTS simulator
Singapore : PMAS provides simulators to their brand new training center
Spain : IES Puerta Bonita installs Flexo Education Pack for 12 concurrent users
Thailand : Kmutt University gets the full range of Sinapse simulators
USA : Forsyth Technical Community College subscribes to Shots e-simulator
USA : Michigan CTI updates its Shots and Flexo simulators
USA : the largest printing company renews simulator usage for its North American plants
Mexico : University Iberoamericana subscribes to Cloud simulators
Latvia : 2 Shots for Riga Technical College
Germany : Stuttgart Media University migrates their simulators to the cloud
China : Tianjin Vocational University installs new sheetfed and Gravure simulators
China : SPPS adds TouchConsoles for Shots and Heatset to its 13 licenses
China : 14 Shots for Shandong Technician Institute
China : Jinjiang Jinxing Vocational installs Shots, Flexo & Gravure simulators
China : Following Shots, the Gravure simulator is now being used by the National Print Skills Contest
Canada : Ryerson's migrates its print simulators to the Cloud and gets more concurrent licenses.
Canada, Burnaby : BCIT renews its installation with a simlab
Australia : TAFE Queensland adds print simulators to its e-learning program for remote apprentices.
Home page
Plan du site
Se connecter
Other languages :
© Sinapse 2017