#include <MSRFieldSignal.hpp>
Encapsulates conversion of MSR bitfields to double signal values in SI units.
- Todo:
- : most implementation is the same as MSREncode class. The hope is that this class can eventually replace the use of MSREncode. The enum for the function comes from the MSR class.
◆ MSRFieldSignal() [1/2]
| geopm::MSRFieldSignal::MSRFieldSignal |
( |
std::shared_ptr< Signal > |
raw_msr, |
|
|
int |
begin_bit, |
|
|
int |
end_bit, |
|
|
int |
function, |
|
|
double |
scalar |
|
) |
| |
- Todo:
- : some of these are not logic errors if MSR data comes from user input files or if this interface is public. Alternatively, checks for these at the json parsing step would make these correctly logic errors.
◆ MSRFieldSignal() [2/2]
◆ ~MSRFieldSignal()
| virtual geopm::MSRFieldSignal::~MSRFieldSignal |
( |
| ) |
|
|
virtualdefault |
◆ operator=()
◆ read()
| double geopm::MSRFieldSignal::read |
( |
void |
| ) |
const |
|
overridevirtual |
Read directly the value of the signal without affecting any pushed batch signals.
Implements geopm::Signal.
◆ sample()
| double geopm::MSRFieldSignal::sample |
( |
void |
| ) |
|
|
overridevirtual |
Apply any conversions necessary to interpret the latest stored value as a double.
Implements geopm::Signal.
◆ setup_batch()
| void geopm::MSRFieldSignal::setup_batch |
( |
void |
| ) |
|
|
overridevirtual |
Prepare the signal for being updated through side effects by the owner's read_batch step. This method should not fail if called multiple times, and ideally only apply the side effects on the first call.
Implements geopm::Signal.
The documentation for this class was generated from the following files:


t
"Sass will make things worse"
"Adding an extra layer of abstraction won't help us"
"Sass encourages bad selectors with nesting"
*Meetup was already 10 years old in 2012
Live style guides are a thing for a reason
github.com/meetup/sassquatch
.specialClass,
.foo a,
.bar .baz p,
.specialList > li a,
fieldset .formThing input
{ ...styles... }
.specialClass,
.foo a,
.bar .baz p,
.specialList > li a,
fieldset .formThing input
{ ...styles... }
.wrapNice
nicolasgallagher.com/about-html-semantics-front-end-architecture/
...not all semantics need to be content-derived
The most reusable components are those with class names that are independent of the content.
* except for the people working with the code
* except microformats, which has been replaced with the HTML5 microdata spec
.unit .docSection:first-child {
padding-top: $spacing;
border-top: 0;
}
.docSection--boxHead {
padding-top: $spacing;
border-top: 0;
}
.promptBox
.promptBox-titlebar
.promptBox-content
.promptBox-actions
.promptBox-button--primary
.promptBox-button--secondary
"Build from the outside in"
-Dale Sande
SassConf 2013
Keep your documentation fresh
github.com/trulia/hologram
/*doc
---
title: Figureset
name: figureset
category: Layout
---
Figure with description. Similar to OOCSS "media block".
```html_example
This is a fluffy kitten
Maybe not the fluffiest, but he'll do.
```
*/
/*doc
---
title: Flushing Elements
name: flushModifiers
category: Modifiers
---
Removes all margin and padding on an element for a given direction.
Class | Description
---------------| ----------------------------------------------------
`flush--top` | Sets `margin` and `padding` to `0` for element top
`flush--right` | Sets `margin` and `padding` to `0` for element right
`flush--bottom`| Sets `margin` and `padding` to `0` for element bottom
`flush--left` | Sets `margin` and `padding` to `0` for element left
`flush--all` | Sets `margin` and `padding` to `0` for all sides
*/
Because cross-platform colors
github.com/meetup/meetup-swatches (prototype)
Elyse Holladay, Jina Bolton
9am-1pm Friday, Resource Room 2nd Fl
social:
name: "EXTERNAL"
comment: "third party colors"
colors:
facebook: [59,89,152,1]
twitter: [51,204,255,1]
linkedin: [72,117,180,1]
tumblr: [43,73,100,1]
flickr: [254,8,131,1]
foursquare: [12,186,223,1]
googleplus: [198,61,45,1]
instagram: [78,67,60,1]
reddit: [206,227,248,1]
wepay: *wepayBlue
Sass, iOS, Android, SVG... and probably more
"twitter": [
0.2,
0.8,
1.0,
1
]...
#ff33ccff
ul .listThing .specialThing
| Inline styles | IDs | Classes | Els & pseudo-els |
|---|---|---|---|
| 0 | 0 | 2 | 1 |
h2 { color: blue; } /* specificity: 1*/
h2 { color: red; } /* specificty: 1 */
!important
!important
!important
!important
!important
!important
!important
http://www.martinfowler.com/
2004
@import "sassquatch.scss";
(the vine)
@import "crustybase.scss";
(the tree)
<jsp:param name="isModernLayout" value="${true}" />
@import "sassquatch.scss";
bower.io
github.com/akdetrick/sassconf
github.com/meetup/sassquatch
github.com/meetup/meetup-swatches
github.com/trulia/hologram
bower.io
making.meetup.com


src/app/shared/services/validation.service.ts
Properties |
Methods |
constructor()
|
| controlHasValidation | ||||||||
controlHasValidation(validators: Array
|
||||||||
|
Checks if validators have been set on the control, an example of a validator being set on a control is: { control: 'informationNeeded', value: 'Information text', validators: ['required'] } TODO: Unit test.
Parameters :
Returns :
boolean
|
| getNgValidationFunctionMap |
getNgValidationFunctionMap()
|
|
Returns a map of how we've mapped simple names to Ng Validators, and in the future custom validators. TODO: Check return in Unit test.
Returns :
any
Array |
| getNgValidators | ||||||||
getNgValidators(validators: Array
|
||||||||
|
Takes in an array of simple validation names. These names map to Ng Validation functions, and can map to more complex custom validation functions. This allows us to leverage the power of Ng Validation, and custom validation, as well as giving us the ability to create reusable validators, that can be used throughout our forms. Note: Validators.minLength requires Validators.required TODO: Unit test.
Parameters :
Returns :
any
|
| isAnyCheckboxChecked | ||||||||||||||||
isAnyCheckboxChecked(formGroup: FormGroup, checkboxes: Array
|
||||||||||||||||
|
isAnyCheckboxChecked Checks if any of the checkbox controls passed to this function are checked ie. have a boolean value of true. This is due to the fact that we might have multiply checkboxes within the view, and the user needs to select at least one of these checkboxes to have entered a valid input. Note that we valid on the formGroup level, and not the control level for this as we are concerned with multiply controls and the Angular 6 way is to have the validator on a common ancestor of controls, in this case our formGroup. If this function returns null, there is no validation error. TODO : Can we return ValidationFn from this? If there the user has checked a checked box, this func, returns null, and therefore no validation error is returned, as the user has checked a box, if it returns a validation error, the user has not checked any of the checkboxes.
Parameters :
Returns :
ValidatorFn | null
|
| isFormControlValid | ||||||||||||
isFormControlValid(formGroup: FormGroup, control: string)
|
||||||||||||
|
Checks if the control is valid. Returns a boolean, based on if the the control, which is part of a form group is valid or not. TODO: Unit test.
Parameters :
Returns :
boolean
|
| isFormGroupInvalid | ||||||||||||
isFormGroupInvalid(formGroup: FormGroup, validationErrorId: string)
|
||||||||||||
|
Is Form Group Invalid Checks if a validation error has been thrown on the pages Angular FormGroup. FormGroup is the common ancestor of FormControls, and therefore and according to the Angular Docs the best place to validate against multiply controls, that have dependencies upon one another. An example being we should check if a user has checked one of eight checkboxes. TODO : Unit Test
Parameters :
Returns :
boolean
|
import {Injectable} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {Validators, ValidationErrors, ValidatorFn} from '@angular/forms';
@Injectable({
providedIn: 'root'
})
export class ValidationService {
// FOR SINGLE CONTROLS - formGroup.control level validation
/**
* Custom validators can be added to this.
*
* TODO : Define interface for array.
* TODO : Add a Custom Validator example.
*
* @see https://angular.io/guide/form-validation#custom-validators
*/
ngValidatorFunctionMap: Array<any> = [
{
simpleName: 'required',
ngValidatorFunction: Validators.required
},
{
simpleName: 'email',
ngValidatorFunction: Validators.email
},
];
constructor() {
}
/**
* Returns a map of how we've mapped simple names to Ng Validators, and in the future custom validators.
*
* TODO: Check return in Unit test.
*
* @return Array
*/
getNgValidationFunctionMap() {
return this.ngValidatorFunctionMap;
}
/**
* Takes in an array of simple validation names.
*
* These names map to Ng Validation functions, and can map to more complex custom validation functions.
*
* This allows us to leverage the power of Ng Validation, and custom validation, as well as giving us
* the ability to create reusable validators, that can be used throughout our forms.
*
* Note: Validators.minLength requires Validators.required
*
* TODO: Unit test.
*
* @see state_meta
* @param validators - ie. ['required', 'email']
*/
getNgValidators(validators: Array<string>) {
let ngValidators: Array<any> = [];
validators.map((validatorName) => {
for (const ngValidatorFunction of this.getNgValidationFunctionMap()) {
if (ngValidatorFunction.simpleName === validatorName) {
ngValidators.push(ngValidatorFunction.ngValidatorFunction);
}
}
});
return ngValidators;
}
/**
* Checks if validators have been set on the control, an example of a validator being set on a control is:
*
* {
* control: 'informationNeeded',
* value: 'Information text',
* validators: ['required']
* }
*
* TODO: Unit test.
*
* @param {Array} validators - ['required']
* @return {boolean}
*/
controlHasValidation(validators: Array<string>): boolean {
return validators && validators.length > 0;
}
/**
* Checks if the control is valid.
*
* Returns a boolean, based on if the the control, which is part
* of a form group is valid or not.
*
* TODO: Unit test.
*
* @param {FormGroup} formGroup
* @param {String} control - 'informationNeeded'
* @return {boolean}
*/
isFormControlValid(formGroup: FormGroup, control: string): boolean {
return formGroup.get(control).valid;
}
// FOR MULTIPLY CONTROLS - formGroup level validation.
/**
* Is Form Group Invalid
*
* Checks if a validation error has been thrown on the pages Angular FormGroup.
*
* FormGroup is the common ancestor of FormControls, and therefore and according to the Angular
* Docs the best place to validate against multiply controls, that have dependencies upon one
* another.
*
* An example being we should check if a user has checked one of eight checkboxes.
*
* TODO : Unit Test
*
* @see ValidationService
* @param {FormGroup} formGroup
* @param {string} validationErrorId - ie. 'reasonsConstentOrderNotApproved' - This is the validation identifier
* we assign to a group of form controls, we assign this when we currently setValidators(), note that we will
* need to pass this in once the Universal Form Builder is merged with Validation.
* @return {boolean}
*/
isFormGroupInvalid(formGroup: FormGroup, validationErrorId: string): boolean {
if (formGroup.errors && formGroup.errors.hasOwnProperty(validationErrorId)) {
return formGroup.errors[validationErrorId];
} else {
return null;
}
}
/**
* isAnyCheckboxChecked
*
* Checks if any of the checkbox controls passed to this function are checked ie. have a boolean value
* of true.
*
* This is due to the fact that we might have multiply checkboxes within the view, and the user needs to
* select at least one of these checkboxes to have entered a valid input.
*
* Note that we valid on the formGroup level, and not the control level for this as we are concerned with
* multiply controls and the Angular 6 way is to have the validator on a common ancestor of controls, in this
* case our formGroup.
*
* If this function returns null, there is no validation error.
*
* TODO : Can we return ValidationFn from this?
*
* If there the user has checked a checked box, this func, returns null, and therefore no validation error is returned,
* as the user has checked a box, if it returns a validation error, the user has not checked any of the checkboxes.
*
* @param formGroup
* @param {string} validationIdentifier - An error name assigned by the developer, this name can then be referred
* to display the view.
* @return {any}
*/
isAnyCheckboxChecked(formGroup: FormGroup, checkboxes: Array<string>, validationIdentifier: string): ValidatorFn | null {
const isAnyCheckboxCheckedValidationFn: ValidatorFn = (controls: FormGroup): ValidationErrors | null => {
for (const checkbox of checkboxes) {
if (controls.get(checkbox).value) {
return null;
}
}
return {
[validationIdentifier]: true,
};
};
return isAnyCheckboxCheckedValidationFn;
}
}


31 October 2007
The Ministry of Health of Indonesia has announced a new case of human infection of H5N1 avian influenza. A 3-year-old male from the Tangerang District, Banten Province developed symptoms on 14 October. The case has recovered.
The investigation found that there were poultry deaths in the case's household prior to his onset of symptoms. The case was living in the same district but had no contact with the previously confirmed 5-year-old female.
Of the 111 cases confirmed to date in Indonesia, 89 have been fatal.


skyline.tsfresh_features package
Submodules
skyline.tsfresh_features.autobuild_features_profile_tables module
This script creates any missing Ionosphere z_fp_ and z_ts_ tables that may be missing from the database using the raw data in the IONOSPHERE_DATA_FOLDER if there is any.
Run the script with your relevant paths and Python version for example:
# BACKUP the skyline MySQL database FIRST
PYTHON_MAJOR_VERSION="2.7"
PYTHON_VIRTUALENV_DIR="/opt/python_virtualenv"
PROJECT="skyline-py2712"
cd "${PYTHON_VIRTUALENV_DIR}/projects/${PROJECT}"
source bin/activate
cd /opt/skyline/github/skyline
python${PYTHON_MAJOR_VERSION} skyline/tsfresh_features/autobuild_features_profile_tables.py
deactivate
skyline.tsfresh_features.generate_tsfresh_features module
This script determines what the known tsfresh feature names are and extracts features from a small timeseries sample of utils/data.json
Then the known TSFRESH_FEATURES are compared to the feature names that were determined from the feature extraction of the sample data set. The script reports changes and outputs a new TSFRESH_FEATURES list.
This is very important and Skyline is using the tsfresh feature names in a relational manner and any changes in tsfresh names or additions must be considered appropriately. Further some tsfresh feature name strings contain spaces and commas so they are not suitable to convert into variables without string manipulation, therefore the TSFRESH_FEATURES array is declared and once feature names are declared they should be treated as immutable objects due to the relational nature of feature profiles.
Run the script with for example:
PYTHON_MAJOR_VERSION="3.8"
PYTHON_VIRTUALENV_DIR="/opt/python_virtualenv"
PROJECT="skyline-py383"
cd "${PYTHON_VIRTUALENV_DIR}/projects/${PROJECT}"
source bin/activate
bin/python${PYTHON_MAJOR_VERSION} skyline/tsfresh_features/generate_tsfresh_features.py
deactivate
Module contents
version info


Flow QML Type
Positions its children side by side, wrapping as necessary More...
| Import Statement: | import QtQuick 2.7 |
| Inherits: |
Properties
- add : Transition
- bottomPadding : real
- effectiveLayoutDirection : enumeration
- flow : enumeration
- layoutDirection : enumeration
- leftPadding : real
- move : Transition
- padding : real
- populate : Transition
- rightPadding : real
- spacing : real
- topPadding : real
Signals
Methods
Detailed Description
The Flow item positions its child items like words on a page, wrapping them to create rows or columns of items.
Below is a Flow that contains various Text items:
Flow { anchors.fill: parent anchors.margins: 4 spacing: 10 Text { text: "Text"; font.pixelSize: 40 } Text { text: "items"; font.pixelSize: 40 } Text { text: "flowing"; font.pixelSize: 40 } Text { text: "inside"; font.pixelSize: 40 } Text { text: "a"; font.pixelSize: 40 } Text { text: "Flow"; font.pixelSize: 40 } Text { text: "item"; font.pixelSize: 40 } }
The Flow item automatically positions the child Text items side by side, wrapping as necessary:
If an item within a Flow is not visible, or if it has a width or height of 0, the item will not be laid out and it will not be visible within the Flow. Also, since a Flow automatically positions its children, a child item within a Flow should not set its x or y positions or anchor itself with any of the anchor properties.
For more information on using Flow and other related positioner-types, see Item Positioners.
See also Column, Row, Grid, Positioner, and Qt Quick Examples - Positioners.
Property Documentation
add : Transition |
This property holds the transition to be run for items that are added to this positioner. For a positioner, this applies to:
- Items that are created or reparented as a child of the positioner after the positioner has been created
- Child items that change their Item::visible property from false to true, and thus are now visible
The transition can use the ViewTransition property to access more details about the item that is being added. See the ViewTransition documentation for more details and examples on using these transitions.
Note: This transition is not applied to the items that are already part of the positioner at the time of its creation. In this case, the populate transition is applied instead.
See also populate, ViewTransition, and Qt Quick Examples - Positioners.
These properties hold the padding around the content.
This QML property was introduced in Qt 5.6.
This property holds the effective layout direction of the flow.
When using the attached property LayoutMirroring::enabled for locale layouts, the visual layout direction of the grid positioner will be mirrored. However, the property layoutDirection will remain unchanged.
See also Flow::layoutDirection and LayoutMirroring.
This property holds the flow of the layout.
Possible values are:
- Flow.LeftToRight (default) - Items are positioned next to to each other according to the layoutDirection until the width of the Flow is exceeded, then wrapped to the next line.
- Flow.TopToBottom - Items are positioned next to each other from top to bottom until the height of the Flow is exceeded, then wrapped to the next column.
This property holds the layout direction of the layout.
Possible values are:
- Qt.LeftToRight (default) - Items are positioned from the top to bottom, and left to right. The flow direction is dependent on the Flow::flow property.
- Qt.RightToLeft - Items are positioned from the top to bottom, and right to left. The flow direction is dependent on the Flow::flow property.
See also Grid::layoutDirection, Row::layoutDirection, and Qt Quick Examples - Right to Left.
These properties hold the padding around the content.
This QML property was introduced in Qt 5.6.
move : Transition |
This property holds the transition to run for items that have moved within the positioner. For a positioner, this applies to:
- Child items that move when they are displaced due to the addition, removal or rearrangement of other items in the positioner
- Child items that are repositioned due to the resizing of other items in the positioner
The transition can use the ViewTransition property to access more details about the item that is being moved. Note, however, that for this move transition, the ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when this transition is triggered by the addition of other items in the positioner; in other cases, these lists will be empty. See the ViewTransition documentation for more details and examples on using these transitions.
Note: In Qt Quick 1, this transition was applied to all items that were part of the positioner at the time of its creation. From QtQuick 2 onwards, positioners apply the populate transition to these items instead.
See also add, ViewTransition, and Qt Quick Examples - Positioners.
These properties hold the padding around the content.
This QML property was introduced in Qt 5.6.
populate : Transition |
This property holds the transition to be run for items that are part of this positioner at the time of its creation. The transition is run when the positioner is first created.
The transition can use the ViewTransition property to access more details about the item that is being added. See the ViewTransition documentation for more details and examples on using these transitions.
See also add, ViewTransition, and Qt Quick Examples - Positioners.
These properties hold the padding around the content.
This QML property was introduced in Qt 5.6.
spacing is the amount in pixels left empty between each adjacent item, and defaults to 0.
See also Grid::spacing.
These properties hold the padding around the content.
This QML property was introduced in Qt 5.6.
Signal Documentation
This signal is emitted when positioning has been completed.
The corresponding handler is onPositioningComplete
.
This QML signal was introduced in Qt 5.9.
Method Documentation
Flow typically positions its children once per frame. This means that inside script blocks it is possible for the underlying children to have changed, but the Flow to have not yet been updated accordingly.
This method forces the Flow to immediately respond to any outstanding changes in its children.
Note: methods in general should only be called after the Component has completed.
This QML method was introduced in Qt 5.9.


--- layout: post title: The reasons why I like Ruby categories: - Ruby tags: - presentation - ruby status: publish type: post published: true meta: _edit_last: '1' _headspace_page_title: The reasons why I like Ruby _headspace_description: Some of the best parts of Ruby that I most like author: login: maxcnunes email<EMAIL_ADDRESS>display_name: maxcnunes first_name: '' last_name: '' ---
Some of the best parts of Ruby that I most like


Welcome! Need help giving feedback?
We are here to help.
Feedback Coach is a tool that helps you feel more confident delivering effective, outcome-oriented feedback.
Welcome! Need help giving feedback?
We are here to help.
Feedback Coach is a tool that helps you feel more confident delivering effective, outcome-oriented feedback.


--- layout: post title: "Refactoring registration flow to functional architecture" description: "An example showing a refactoring from F# partial application 'dependency injection' to an impure/pure/impure sandwich." date: 2019-12-02 8:19 UTC tags: [F#, Functional Programming] image: "/content/binary/complete-registration-workflow-with-2fa-difficult-to-sandwich.png" image_alt: "A flowchart describing the workflow for completing a registration." --- {% include JB/setup %}
{{ page.description }}
In a comment to Dependency rejection, I wrote:
"I'd welcome a simplified, but still concrete example where the impure/pure/impure sandwich described here isn't going to be possible."Christer van der Meeren kindly replied with a suggestion.
The code in question relates to validation of user accounts. You can read the complete description in the linked comment, but I'll try to summarise it here. I'll then show a refactoring to a functional architecture - specifically, to an impure/pure/impure sandwich.
The code is available on GitHub.
The system in question uses two-factor authentication with mobile phones. When you sign up for the service, you give your phone number. You then receive an SMS, and must use whatever is in that SMS to prove ownership of the phone number. Christer van der Meeren illustrates the flow like this:
He also supplies sample code:
let completeRegistrationWorkflow (createProof: Mobile -> Async<ProofId>) (verifyProof: Mobile -> ProofId -> Async<bool>) (completeRegistration: Registration -> Async<unit>) (proofId: ProofId option) (registration: Registration) : Async<CompleteRegistrationResult> = async { match proofId with | None -> let! proofId = createProof registration.Mobile return ProofRequired proofId | Some proofId -> let! isValid = verifyProof registration.Mobile proofId if isValid then do! completeRegistration registration return RegistrationCompleted else let! proofId = createProof registration.Mobile return ProofRequired proofId }
While this is F#, it's not functional, since it uses partial application for dependency injection. From the description, I find it safe to assume that we can consider Async as a surrogate for IO.
The code implies the existence of other types. I decided to define them like this:
type Mobile = Mobile of int type ProofId = ProofId of Guid type Registration = { Mobile : Mobile } type CompleteRegistrationResult = ProofRequired of ProofId | RegistrationCompleted
In reality, they're probably more complicated, but this is enough to make the code compile.
Is it possible to refactor completeRegistrationWorkflow
to an impure/pure/impure sandwich?
It is possible to refactor completeRegistrationWorkflow
to an impure/pure/impure sandwich. You'll see how to do that soon. Before we start that work, however, I'd like to warn against jumping to conclusions. It's possible that the problem statement doesn't capture some subtleties that one would have to deal with in the real world. It's also possible that I've misunderstood the essence of Christer van der Meeren's problem description.
It's (relatively) easy to teach the basics of programming. You teach a beginner about keywords, programming constructs, how to compile or interpret a program, and so on.
On the other hand, it's hard to write about dealing with complicated code. There are ways to make legacy code better, but the moves you have to make depend on myriad details. Complicated code is, by definition, something that's hard to learn. This means that truly complicated legacy code is rarely suitable for instructive examples. One has to strike a delicate balance and produce an example that looks complicated enough to warrant improvement, but on the other hand still be simple enough to be understood.
I think that Christer van der Meeren has struck that balance. With three dependencies, the sample code looks just complicated enough to warrant refactoring. On the other hand, you can understand what it's supposed to do in a few minutes. There's a risk, however, that the example is too simplified. That could weaken the result of the refactoring that follows. Could you still apply that refactoring if the problem was more complicated?
It's my experience that it's conspicuously often possible to implement an impure/pure/impure sandwich.
In the rest of this article, I want to show how to refactor completeRegistrationWorkflow
to an impure/pure/impure sandwich. As Refactoring admonishes:
Right now, however, there's no tests, so I'm going to add some."to refactor, the essential precondition is [...] solid tests"
The tests will need some Test Doubles to stand in for the three dependency functions. If possible, I prefer state-based testing over interaction-based testing. First, then, we need some Fakes.
While completeRegistrationWorkflow
takes three dependency functions, it looks as though there's only two architectural dependencies:
type Fake2FA () = let mutable proofs = Map.empty member _.CreateProof mobile = match Map.tryFind mobile proofs with | Some (proofId, _) -> proofId | None -> let proofId = ProofId (Guid.NewGuid ()) proofs <- Map.add mobile (proofId, false) proofs proofId |> fun proofId -> async { return proofId } member _.VerifyProof mobile proofId = match Map.tryFind mobile proofs with | Some (_, true) -> true | _ -> false |> fun b -> async { return b } member _.VerifyMobile mobile = match Map.tryFind mobile proofs with | Some (proofId, _) -> proofs <- Map.add mobile (proofId, true) proofs | _ -> ()
In F#, I find that the easiest way to model a mutable resource is to use an object. This one just keeps track of a collection of proofs. The CreateProof
method fits the function signature of completeRegistrationWorkflow
's createProof
function argument. It looks for an existing proof for the mobile number so that it can reuse the same proof multiple times. If there's no proof for mobile
, it creates a new Guid
and returns it after having first added it to the collection.
Likewise, the VerifyProof
method fits the type of the verifyProof
function argument. Proofs are actually tuples of IDs and a flag that keeps track of whether or not they've been verified. The method returns the flag if it's there, and false
otherwise.
The third VerifyMobile
method is a test-specific functionality that enables a test to mark a proof as having been verified via two-factor authentication.
Compared to Fake2FA
, the Fake registration database is simple:
type FakeRegistrationDB () = inherit Collection<Registration> () member this.CompleteRegistration r = async { this.Add r }
Again, the CompleteRegistration
method fits the completeRegistration
function argument to completeRegistrationWorkflow
. It just makes the inherited Add
method Async
.
My plan is to add Characterisation Tests so that I can refactor. I do, however, plan to change the API of the System Under Test (SUT). This could break the tests, which would defy their purpose. To protect against this, I'll test against a Facade. Initially, this Facade will be equivalent to the completeRegistrationWorkflow
function, but this will change as I refactor.
In addition to the SUT Facade, the tests will also need access to the 'injected' dependencies. You can address this by creating a Fixture Object:
let createFixture () = let twoFA = Fake2FA () let db = FakeRegistrationDB () let sut = completeRegistrationWorkflow twoFA.CreateProof twoFA.VerifyProof db.CompleteRegistration sut, twoFA, db
This function return a triple of values: the SUT Facade and the two Fakes.
The SUT Facade is a partially applied function of the type ProofId option -> Registration -> Async<CompleteRegistrationResult>
. In other words, it abstracts away the specifics about how impure actions are executed. It seems reasonable to imagine that the two remaining input arguments, ProofId option
and Registration
, are run-time values. Regardless of refactoring, the resulting function should be able to receive those arguments and produce the desired outcome.
It looks like the cyclomatic complexity of completeRegistrationWorkflow
is 3, so you're going to need three Characterisation Tests. You can add them in any order you like, but in this case I found it natural to follow the order in which the branches are laid out in the SUT.
This test case verifies what happens if the proof ID is missing:
[<Theory>] [<InlineData 123>] [<InlineData 432>] let ``Missing proof ID`` mobile = async { let sut, twoFA, db = createFixture () let r = { Mobile = Mobile mobile } let! actual = sut None r let! expectedProofId = twoFA.CreateProof r.Mobile let expected = ProofRequired expectedProofId expected =! actual test <@ Seq.isEmpty db @> }
All the tests in this article use xUnit.net 2.4.0 with Unquote 5.0.0.
This test calls the sut
Facade with a None
proof ID and an arbitrary Registration
r
. Had I used a property-based testing framework such as FsCheck or Hedgehog, I could have made the Registration
value itself an arbitrary test argument, but I thought that this was overkill for this situation.
In order to figure out the expectedProofId
, the test relies on the behaviour of the Fake2FA
class. The CreateProof
method is idempotent, so calling it several times with the same number should return the same proof. In this test case, we expect the sut
to have done so already, so calling the method once more from the test should return the same value that the SUT received. The test then wraps the proof ID in the ProofRequired
case and uses Unquote's =!
(must equal) operator to verify that expected
is equal to actual
.
Finally, the test also verifies that the reservations database remains empty.
Since this is a Characterisation Test it already passes, which makes it untrustworthy. How do I know that I didn't write a Tautological Assertion?
When I write Characterisation Tests, I always try to change the SUT to verify that the test fails for the appropriate reason. In order to fail the first assertion, I can make this change to the None
branch of the SUT:
match proofId with | None -> //let! proofId = createProof registration.Mobile let proofId = ProofId (Guid.NewGuid ()) return ProofRequired proofId
This fails the expected =! actual
assertion, as expected.
Likewise, you can fail the second assertion with this change:
match proofId with | None -> do! completeRegistration registration let! proofId = createProof registration.Mobile return ProofRequired proofId
The addition of the completeRegistration
statement causes the test <@ Seq.isEmpty db @>
assertion to fail, again as expected.
Now I trust that test.
Next, you have the case where all is good. The proof ID is present and valid. You can characterise the behaviour with this test:
[<Theory>] [<InlineData 987>] [<InlineData 247>] let ``Valid proof ID`` mobile = async { let sut, twoFA, db = createFixture () let r = { Mobile = Mobile mobile } let! p = twoFA.CreateProof r.Mobile twoFA.VerifyMobile r.Mobile let! actual = sut (Some p) r RegistrationCompleted =! actual test <@ Seq.contains r db @> }
This test uses CreateProof
to create a proof before the sut
is exercised. It also uses the test-specific VerifyMobile
method to mark the mobile number (and thereby the proof) as valid.
Again, there's two assertions: one against the return value actual
, and one that verifies that the registration database db
now contains the registration r
.
As before, you can't trust a Characterisation Test before you've seen it fail, so first edit the isValid
branch of the SUT like this:
if isValid then do! completeRegistration registration //return RegistrationCompleted return ProofRequired proofId
This fails the RegistrationCompleted =! actual
assertion, as expected.
Now make this change:
if isValid then //do! completeRegistration registration return RegistrationCompleted
Now the test <@ Seq.contains r db @>
assertion fails, as expected.
This test also seems trustworthy.
The final test case is when a proof ID exists, but it's invalid:
[<Theory>] [<InlineData 327>] [<InlineData 666>] let ``Invalid proof ID`` mobile = async { let sut, twoFA, db = createFixture () let r = { Mobile = Mobile mobile } let! p = twoFA.CreateProof r.Mobile let! actual = sut (Some p) r let! expectedProofId = twoFA.CreateProof r.Mobile let expected = ProofRequired expectedProofId expected =! actual test <@ Seq.isEmpty db @> }
The arrange phase of the test is comparable to the previous test case. The only difference is that the new test doesn't invoke twoFA.VerifyMobile r.Mobile
. This leaves the generated proof ID p
invalid.
The assertions, on the other hand, are identical to those of the Missing proof ID
test case, which means that you can make the same edits to the else
branch as you can to the None
branch, as described above. If you do that, the assertions fail as they're supposed to. You can also trust this Characterisation Test.
While I want to keep the SUT Facade's type unchanged, I do want change the way I compose it. The goal is an impure/pure/impure sandwich: Do something impure first, then call a pure function with the data obtained, and finally do something impure with the output of the pure function.
This means that the composition is going to manipulate the input values to the SUT Facade. To make that easier, I perform an eta conversion on the sut
:
let createFixture () = let twoFA = Fake2FA () let db = FakeRegistrationDB () let sut pid r = completeRegistrationWorkflow twoFA.CreateProof twoFA.VerifyProof db.CompleteRegistration pid r sut, twoFA, db
This doesn't change the behaviour or how the SUT is composed. It only makes the pid
and r
arguments explicitly visible.
When you consider the current implementation of completeRegistrationWorkflow
, it seems that the impure actions are interleaved with the decision-making code. How to separate them?
The first opportunity that I identified was that it always calls verifyProof
in the Some
case. Whenever you want to call a method only in the Some
case, but not in the None
case, it suggest Option.map
.
It should be possible to run Option.map (twoFA.VerifyProof r.Mobile) pid
as the initial impure action of the impure/pure/impure sandwich. If that's possible, we could pass the output of that pure function as an argument to completeRegistrationWorkflow
. That would already make it simpler:
let completeRegistrationWorkflow (createProof: Mobile -> Async<ProofId>) (completeRegistration: Registration -> Async<unit>) (proof: bool option) (registration: Registration) : Async<CompleteRegistrationResult> = async { match proof with | None -> let! proofId = createProof registration.Mobile return ProofRequired proofId | Some isValid -> if isValid then do! completeRegistration registration return RegistrationCompleted else let! proofId = createProof registration.Mobile return ProofRequired proofId }
Notice that by changing the proof
argument to a bool option
, you no longer need to call verifyProof
, so you can remove it.
There's just one problem. The result of Option.map (twoFA.VerifyProof r.Mobile) pid
is an Option<Async<bool>>
, but you need an Option<bool>
.
You can compose the SUT Facade in an asynchronous workflow, and use a let!
binding, but that's not going to solve the problem. A let!
binding only works when the outer container is Async
. Here, the outermost container is Option
. You're going to need to flip the containers around so that you get an Async<Option<bool>>
that you can let!
-bind:
let sut pid r = async { let! p = match Option.map (twoFA.VerifyProof r.Mobile) pid with | Some b -> async { let! b' = b return Some b' } | None -> async { return None } return! completeRegistrationWorkflow twoFA.CreateProof db.CompleteRegistration p r }
By pattern-matching on Option.map (twoFA.VerifyProof r.Mobile) pid
, you can return one of two alternative asynchronous workflows.
Due to the let!
binding, p
is a bool option
that you can pass to completeRegistrationWorkflow
.
I know what you're going to say. You'll protest that I just moved complex behaviour out of completeRegistrationWorkflow
. The implied assumption here is that completeRegistrationWorkflow
is the top-level behaviour that you'd compose in a Composition Root. The createFixture
function plays that role in this refactoring exercise.
You'd normally view the Composition Root as a Humble Object - an object that we accept isn't covered by tests because it has a cyclomatic complexity of one. This is no longer the case.
The conversion of Option<Async<bool>>
to Async<Option<bool>>
is, however, a well-known operation. In Haskell this is known as a traversal, and it's a completely generic operation:
// ('a -> Async<'b>) -> 'a option -> Async<'b option> let traverse f = function | Some x -> async { let! x' = f x return Some x' } | None -> async { return None }
You can put this function in a general-purpose module called AsyncOption
and cover it by unit tests if you will. You can even put this module in a separate library; it's perfectly decoupled from the the specifics of the registration flow domain.
If you do that, completeRegistrationWorkflow
doesn't change, but the composition does:
let sut pid r = async { let! p = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid return! completeRegistrationWorkflow twoFA.CreateProof db.CompleteRegistration p r }
You're now back where you'd like to be: One impure action produces a value that you can pass to another function. There's no explicit branching in the code. The cyclomatic complexity remains one.
That first refactoring takes care of one out of three impure dependencies. Next, you can get rid of createProof
. This one seems to be more difficult to get rid of. It doesn't seem to be required only in the Some
case, so a map
or traverse
can't work. In both cases, however, the result of calling createProof
is handled in exactly the same way.
Here's another common trick in functional programming: Decouple decisions from effects. Return a value that indicates the decision that the function reaches, and then let the second impure action of the impure/pure/impure sandwich act on the decision.
In this case, you can model your decision as a Mobile option
. You might want to consider a more explicit type, in order to better communicate intent, but it's best to keep each refactoring step small:
let completeRegistrationWorkflow (completeRegistration: Registration -> Async<unit>) (proof: bool option) (registration: Registration) : Async<Mobile option> = async { match proof with | None -> return Some registration.Mobile | Some isValid -> if isValid then do! completeRegistration registration return None else return Some registration.Mobile }
Notice that the createProof
dependency is no longer required. I've removed it from the argument list of completeRegistrationWorkflow
.
The composition now looks like this:
let createFixture () = let twoFA = Fake2FA () let db = FakeRegistrationDB () let sut pid r = async { let! p = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid let! res = completeRegistrationWorkflow db.CompleteRegistration p r let! pidr = AsyncOption.traverse twoFA.CreateProof res return pidr |> Option.map ProofRequired |> Option.defaultValue RegistrationCompleted }
Thanks to the let!
binding, the result res
is a Mobile option
. You can now let the twoFA.CreateProof
method traverse
over res
. This produces an Async<Option<ProofId>>
that you can let!
-bind to pidr
- a ProofId option
.
You can use Option.map
to wrap the ProofId
value in a ProofRequired
case, if it's there. This step of the final pipeline produces a CompleteRegistrationResult option
.
Finally, you can use Option.defaultValue
to fold the option
into a CompleteRegistrationResult
. The default value is RegistrationCompleted
. This is the case value that'll be used if the option
is None
.
Again, the composition has a cyclomatic complexity of one, and the type of the sut
remains ProofId option -> Registration -> Async<CompleteRegistrationResult>
. This is a true refactoring. The type of the SUT remains the same, and no behaviour changes. The tests still pass, even though I haven't had to edit them.
Consider the intent of completeRegistrationWorkflow
. The purpose of the operation is to complete a registration workflow. The name is quite explicit. Thus, the happy path is when the proof ID is valid and the function can call completeRegistration
.
Usually, when you call a function that returns an option
, the implied contract is that the Some
case represents the happy path. That's not the case here. The Some
case carries information about the error paths. This isn't idiomatic.
It'd be more appropriate to use a Result
return value:
let completeRegistrationWorkflow (completeRegistration: Registration -> Async<unit>) (proof: bool option) (registration: Registration) : Async<Result<unit, Mobile>> = async { match proof with | None -> return Error registration.Mobile | Some isValid -> if isValid then do! completeRegistration registration return Ok () else return Error registration.Mobile }
This change is in itself small, but it does require some changes to the composition. Just as you had to add an Option.traverse
function when the return type was an option
, you'll now have to add similar functionality to Result
. Result is also known as Either. Not only is it a bifunctor, you can also traverse both axes. Haskell calls this a bitraversable
functor.
// ('a -> Async<'b>) -> ('c -> Async<'d>) -> Result<'a,'c> -> Async<Result<'b,'d>> let traverseBoth f g = function | Ok x -> async { let! x' = f x return Ok x' } | Error e -> async { let! e' = g e return Error e' }
Here I just decided to call the function traverseBoth
and the module AsyncResult
.
You're also going to need the equivalent of Option.defaultValue
for Result
. Something that translates both dimensions of Result
into the same type. That's the Either catamorphism, so you could, for example, introduce another general-purpose function called cata
:
// ('a -> 'b) -> ('c -> 'b) -> Result<'a,'c> -> 'b let cata f g = function | Ok x -> f x | Error e -> g e
This is another entirely general-purpose function that you can put in a general-purpose module called Result
, in a general-purpose library. You can also cover it by unit tests, if you like.
These two general-purpose functions enable you to compose the workflow:
let createFixture () = let twoFA = Fake2FA () let db = FakeRegistrationDB () let sut pid r = async { let! p = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid let! res = completeRegistrationWorkflow db.CompleteRegistration p r let! pidr = AsyncResult.traverseBoth (fun () -> async { return () }) twoFA.CreateProof res return pidr |> Result.cata (fun () -> RegistrationCompleted) ProofRequired } sut, twoFA, db
This looks more confused than previous iterations. From here, though, it'll get better again. The first two lines of code are the same as before, but now res
is a Result<unit, Mobile>
. You still need to let twoFA.CreateProof
traverse the 'error path', but now you also need to take care of the happy path.
In the Ok
case you have a unit
value (()
), but traverseBoth
expects its f
and g
functions to return Async
values. I could have fixed that with a more specialised traverseError
function, but we'll soon move on from here, so it's hardly worthwhile.
In Haskell, you can 'elevate' a value simply with the pure
function, but in F#, you need the more cumbersome (fun () -> async { return () })
to achieve the same effect.
The traversal produces pidr
(for Proof ID Result) - a Result<unit, ProofId>
value.
Finally, it uses Result.cata
to turn both the Ok
and Error
dimensions into a single CompleteRegistrationResult
that can be returned.
There's still one dependency left: the completeRegistration
function, but it's now trivial to remove. Instead of calling the dependency function from within completeRegistrationWorkflow
you can use the same trick as before. Decouple the decision from the effect.
Return information about the decision the function made. In the above incarnation of the code, the Ok
dimension is currently empty, since it only returns unit
. You can use that 'channel' to communicate that you decided to complete a registration:
let completeRegistrationWorkflow (proof: bool option) (registration: Registration) : Async<Result<Registration, Mobile>> = async { match proof with | None -> return Error registration.Mobile | Some isValid -> if isValid then return Ok registration else return Error registration.Mobile }
This is another small change. When isValid
is true
, the function no longer calls completeRegistration
. Instead, it returns Ok registration
. This means that the return type is now Async<Result<Registration, Mobile>>
. It also means that you can remove the completeRegistration
function argument.
In order to compose this variation, you need one new general-purpose function. Perhaps you find this barrage of general-purpose functions exhausting, but it's an artefact of a design philosophy of the F# language. The F# base library contains only few general-purpose functions. Contrast this with GHC's base library, which comes with all of these functions built in.
The new function is like Result.cata
, but over Async<Result<_>>
.
// ('a -> 'b) -> ('c -> 'b) -> Async<Result<'a,'c>> -> Async<'b> let cata f g r = async { let! r' = r return Result.cata f g r' }
Since this function does conceptually the same as Result.cata
I decided to retain the name cata
and just put it in the AsyncResult
module. (This may not be strictly correct, as I haven't really given a lot of thought to what a catamorphism for Async
would look like, if one exists. I'm open to suggestions about better naming. After all, cata
is hardly an idiomatic F# name.)
With AsyncResult.cata
you can now compose the system:
let sut pid r = async { let! p = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid let! res = completeRegistrationWorkflow p r return! res |> AsyncResult.traverseBoth db.CompleteRegistration twoFA.CreateProof |> AsyncResult.cata (fun () -> RegistrationCompleted) ProofRequired }
Not only did the call to completeRegistrationWorkflow
get even simpler, but you also now avoid the awkwardly named pidr
value. Thanks to the let!
binding, res
has the type Result<Registration, Mobile>
.
Note that you can now let both impure actions (db.CompleteRegistration
and twoFA.CreateProof
) traverse the result. This step produces an Async<Result<unit, ProofId>>
that's immediately piped to AsyncResult.cata
. This reduces the two alternative dimensions of the Result
to a single Async<CompleteRegistrationResult>
value.
The completeRegistrationWorkflow
function now begs to be further simplified.
Once you remove all dependencies, your domain logic doesn't have to be asynchronous. Nothing asynchronous happens in completeRegistrationWorkflow
, so simplify it:
let completeRegistrationWorkflow (proof: bool option) (registration: Registration) : Result<Registration, Mobile> = match proof with | None -> Error registration.Mobile | Some isValid -> if isValid then Ok registration else Error registration.Mobile
Gone is the async
computation expression, including the return
keyword. This is now a pure function.
You'll have to adjust the composition once more, but it's only a minor change:
let sut pid r = async { let! p = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid return! completeRegistrationWorkflow p r |> AsyncResult.traverseBoth db.CompleteRegistration twoFA.CreateProof |> AsyncResult.cata (fun () -> RegistrationCompleted) ProofRequired }
The result of invoking completeRegistrationWorkflow
is no longer an Async
value, so there's no reason to let!
-bind it. Instead, you can call it and immediately pipe its output to AsyncResult.traverseBoth
.
Consider completeRegistrationWorkflow
. Can you make it simpler?
At this point it should be evident that two of the branches contain duplicate code. Applying the DRY principle you can simplify it:
let completeRegistrationWorkflow (proof: bool option) (registration: Registration) : Result<Registration, Mobile> = match proof with | Some true -> Ok registration | _ -> Error registration.Mobile
I'm not too fond of this style of type annotation for simple functions like this, so I'd like to remove it:
let completeRegistrationWorkflow proof registration = match proof with | Some true -> Ok registration | _ -> Error registration.Mobile
These two steps are pure refactorings: they only reorganise the code that implements completeRegistrationWorkflow
, so the composition doesn't change.
While reading this article, you may have felt frustration gather. This is cheating! You took out all of the complexity. Now there's nothing left! You're likely to feel that I've moved a lot of behaviour into untestable code. I've done nothing of the sort.
I'll remind you that while functions like AsyncOption.traverse
and AsyncResult.cata
do contain branching behaviour, they can be tested. In fact, since they're pure functions, they're intrinsically testable.
It's true that a composition of a pure function with its impure dependencies may not be (unit) testable, but that's also true for a Dependency Injection-based object graph composed in a Composition Root.
Compositions of functions may look non-trivial, but to a degree, the type system will assist you. If your composition compiles, it's likely that you've composed the impure/pure/impure sandwich correctly.
Did I take out all the complexity? I didn't. There's a bit left; the function now has a cyclomatic complexity of two. If you look at the original function, you'll see that the duplication was there all along. Once you remove all the accidental complexity, you uncover the essential complexity. This happens to me so often when I apply functional programming principles that I fancy that functional programming is a silver bullet.
We're mostly done now. The problem now appears in all its simplicity, and you have an impure/pure/impure sandwich.
You can still improve the code, though.
If you consider the current composition, you may find that p
isn't the best variable name. I admit that I struggled with naming that variable. Sometimes, variable names are in the way and the code might be clearer if you could elide them by composing a pipeline of functions.
That's always worth an attempt. This time, ultimately I find that it doesn't improve things, but even an attempt can be illustrative.
If you want to eliminate a named value, you can often do so by piping the output of the function that produced the variable directly to the next function. This does, however, require that the function argument is the right-most. Currently, that's not the case. registration
is right-most, and proof
is to the left.
There's no compelling reason that the arguments should come in that order, so flip them:
let completeRegistrationWorkflow registration proof = match proof with | Some true -> Ok registration | _ -> Error registration.Mobile
This enables you to write the entire composition as a single pipeline:
let sut pid r = async { return! AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid |> Async.map (completeRegistrationWorkflow r) |> Async.bind ( AsyncResult.traverseBoth db.CompleteRegistration twoFA.CreateProof >> AsyncResult.cata (fun () -> RegistrationCompleted) ProofRequired) }
This does, however, call for two new general-purpose functions: Async.map
and Async.bind
:
// ('a -> 'b) -> Async<'a> -> Async<'b> let map f x = async { let! x' = x return f x' } // ('a -> Async<'b>) -> Async<'a> -> Async<'b> let bind f x = async { let! x' = x return! f x' }
In my opinion, these functions ought to belong to F#'s Async
module, but for for reasons that aren't clear to me, they don't. As you can see, though, they're easy to add.
While the this change gets rid of the p
variable, I don't think it makes the overall composition easier to understand. The action of swapping the function arguments does, however, enable another simplification.
Now that proof
is completeRegistrationWorkflow
's last function argument, you can perform an eta reduction:
let completeRegistrationWorkflow registration = function | Some true -> Ok registration | _ -> Error registration.Mobile
Not everyone is a fan of the point-free style, but I like it. YMMV.
Regardless of whether you prefer completeRegistrationWorkflow
in point-free or pointed style, I think that the composition needs improvement. It should explicitly communicate that it's an impure/pure/impure sandwich. This makes it necessary to reintroduce some variables, so I'm also going to bite the bullet and devise some better names.
let sut pid r = async { let! validityOfProof = AsyncOption.traverse (twoFA.VerifyProof r.Mobile) pid let decision = completeRegistrationWorkflow r validityOfProof return! decision |> AsyncResult.traverseBoth db.CompleteRegistration twoFA.CreateProof |> AsyncResult.cata (fun () -> RegistrationCompleted) ProofRequired }
Instead of p
, I decided to call the first value validityOfProof
. This is the result of the first impure action in the sandwich (the upper slice of bread).
While validityOfProof
is the result of an impure action, the value itself is pure and can be used as input to completeRegistrationWorkflow
. This is the pure part of the sandwich. I called the output decision
because the workflow makes a decision based on its input, and it's up to the caller to act on that decision.
Notice that decision
is bound with a let
binding (instead of a let!
binding), despite taking place inside an async
workflow. This is because completeRegistrationWorkflow
is pure. It doesn't return an Async
value.
The second impure action acts on decision
through a pipeline of AsyncResult.traverseBoth
and AsyncResult.cata
, as previously explained.
I think that the impure/pure/impure sandwich is more visible like this, so that was my final edit. I'm happy with how it looks now.
I don't claim that you can always refactor code to an impure/pure/impure sandwich. In fact, I can easily envision categories of software where such an architecture seems impossible.
Still, I find it intriguing that when I find myself in the realm of web services or message-based applications, I can't recall a case where a sandwich has been impossible. Surely, there must cases where it is so. That's the reason that I solicit examples. This article was a response to such an example. I found it fruitful, because it enabled me to discuss several useful techniques for composing behaviour in a functional architecture. On the other hand, it failed to be a counter-example.
I'm sure that some readers are left with a nagging doubt. That's all very impressive, but would you actually write code like that in a piece of production software?
If it was up to me, then: yes. I find that when I can keep code pure, it's trivial to unit test and there's no test-induced damage. Functions also compose in a way objects don't easily do, so there's many advantages to functional programming. I'll take them when they're available.
As always, context matters. I've been in team settings where other team members would embrace this style of programming, and in other environments where team members wouldn't understand what was going on. In the latter case, I'd adjust my approach to challenge, not alienate, other team members.
My intention with this article was to show what's possible, not to dictate what you should do. That's up to you.
This article is the December 2 entry in the F# Advent Calendar in English 2019.
Comments
Thank you so much for the comprehensive reply to my comment. It was very instructive to see refactoring process, from thought to code. The post is an excellent reply to the question I asked.
A slight modification
In my original comment, I made one simplification that, in hindsight, I perhaps should not have made. It is not critical, but it complicates things slightly. In reality, the
completeRegistration
function does not returnAsync<unit>
, butAsync<Result<unit, CompleteRegistrationError>>
(where, currently,CompleteRegistrationError
has the single caseUserExists
, returned if the DB throws a unique constraint error).As I see it, the impact of this to your refactoring is two-fold:
AsyncResult.traverseBoth
, since the signatures between the two cases aren't compatible (unless you want to mess around with nestedResult
values). You could write a customtraverse
function just for the needed signature, but then we’ve traveled well into the lands of “generic does not imply general”.Result
being reserved for actual errors.Evaluating the refactoring
My original comment ended in the following question (emphasis added):
With this (vague) question and the above modifications in mind, let's look at the relevant code before/after. In both cases, there are two functions: The workflow/logic, and the composition.
Before
Before refactoring, we have a slightly complex impure workflow (which still is fairly easily testable using state-based testing, as you so aptly demonstrated) – note the
asyncResult
CE (I’m using the excellent FsToolkit.ErrorHandling, if anyone wonders) and the updated signatures; otherwise it’s the same:Secondly, we have the trivial "humble object" composition, which looks like this:
The composition is, indeed, humble – the only thing it does is call the higher-order workflow function with the correct parameters. It has no cyclomatic complexity and is trivial to read, and I don't think anyone would consider it necessary to test.
After
After refactoring, we have the almost trivial pure function we extracted (for simplicity I let it return
Result
here, as you proposed):Secondly, we have the composition function. Now, with the modification to
completeRegistration
(returningAsync<Result<_,_>>
), it can't as easily be written in point-free style. You might certainly be able to improve it, but here is my quick initial take.Evaluation
Now that we have presented the code before/after, let us take stock of what we have gained and lost by the refactoring.
Pros:
Cons:
AsyncOption.traverse
,AsyncResult.traverseBoth
,AsyncResult.cata
, etc.Returning to my initial question: Does the refactoring “reduce complexity where it matters?“ I’m not sure. This is (at least partly) “personal opinions” territory, of course, and my vague question doesn’t help. But personally I find the result of the refactoring more complex to understand than the original, DI workflow-based version.
Based on Scott Wlaschin’s book Domain Modelling Made Functional, it’s possible he might agree. He seems very fond of the “DI workflow” approach there. I personally prefer a bit more dependency rejection than that, because I find “DR”/sandwiches often leads to simpler code, but in this particular case, I may prefer the impure DI workflow, tested using state-based testing. At least for the more complex code I described, but perhaps also for your original example.
Still, I truly appreciate your taking the time to respond in this manner. It was very instructive, as always, which was after all the point. And you’re welcome to share any insights regarding this comment, too.
Christer, thank you for writing. This is great! One of your comments inspires me to compose another article that I've long wanted to write. If I manage to produce it in time, I'll publish it Monday. Once that's done, I'll respond here in a more thorough manner.
When I do that, however, I don't plan to reproduce your updated example, or address it in detail. I see nothing in it that invalidates what I've already written. As far as I can tell, you don't need to explicitly pattern-match on
completePure reg proofValidity
. You should be able to map or traverse over it like already shown. If you want my help with the details, I'll be happy to do so, but then please prepare a minimal working example like I did for this article. You can either fork my example or make a new repository.This is a fantastic post Mark! Thank you very much for going step-by-step while explaining how you refactored this code.
I would like to suggest a example in the realm of web services or message-based applications that cannot be expressed as a impure/pure/impure sandwich.
Let's call an "impure/pure/impure sandwich" an impure-pure-impure composition. More generally, any impure funciton can be expressed as a composition of the form
[pure-]impure(-pure-impure)*[-pure]
. That is, (1) it might begin with a pure step, then (2) there is an impure step, then (3) there is a sequence of length zero or more containing a pure step followed by an impure step, and lastly (4) it might end with another pure step. One reason an impure fucntion might intentially be expressed by a composition that ends with a pure step is to erase senitive informaiton form the memory hierarchy. For simplicity though, let's assume that any impure function can be refactored so that the corresponding composition ends with an impure step. Let the length of a composition be one plus the number of dashes (-
) that it contains.Suppose
f
is a function with an impure-pure-impure composition such thatf
cannot be refactored to a fucntion with a composition of a smaller length. Then there exists fucntionf'
with a pure-impure-pure-impure composition. The construction uses public-key cryptography. I think this is a natural and practical example.Here is the definition of
f'
in words. The user sends to the server ciphertext encryped using the server's public key. The user's request is received by a process that already has the server's private key loaded into memory. This process decrypts the user's ciphertext using its private key to obtain some plantextp
. This step is pure. Then the process passesp
intof
.Using symmetric-key cryptography, it is possible to construct a function with a composition of an arbitrarily high length. The following construction reminds me of how union routing works (though each decryption in that case is intended to happen in a different process on a different server). I admit that this example is not very natural or practical.
Suppose
f
is a function with a composition of lengthn
. Then there exists fucntionf'
with a composition of length greater thann
. Specifically, if the original composition starts with a pure step, then the length is larger by one; if the original composition starts with an impure step, then the length is larger by two.Here is the definition of
f'
in words. The user sends to the server an ID and ciphertext encryped using a symmetric key that corresponds to the ID. The user's request is received by a process that does not have any keys loaded into memory. First, this process obtains from disk the appropriate symmetric key using the ID. This step is impure. Then this process decrypts the user's ciphertext using this key to obtain some plantextp
. This step is pure. Then the process passesp
intof
.Tyson, thank you for writing. Unfortunately, I don't follow your chain of reasoning. Cryptography strikes me as fitting the impure/pure/impure sandwich architecture quite well. There's definitely an initial impure step because you have to initialise a random number generator, as well as load keys, salts, and whatnot from storage. From there, though, the cryptographic algorithms are, as far as I'm aware, pure calculation. I don't see how asymmetric cryptography changes that.
The reason that I'm soliciting examples that defy the impure/pure/impure sandwich architecture, however, is that I'm looking for a compelling example. What to do when the sandwich architecture is impossible is a frequently asked question. To be clear, I know what to do in that situation, but I'd like to write an article that answers the question in a compelling way. For that, I need an example that an uninitiated reader can follow.
Sorry that my explanation was unclear. I should have included an example.
I agree that cyptographic algorithms are pure. From your qoute that I included above, I get the impression that you have neglected to consider what computation is to be done with the output of the cyptogrpahic algorithm.
Here is a specific example of my first construction, which uses public-key cyptography. Consider the function
sut
that concluded your post. I repeat it for clarity.Let
sut
be the functionf
in that construction. In particular,sut
is an impure/pure/impure sandwich, or equivalently an impure-pure-impure composition that of course has length 3. Furthermore, I think it is clear that this behavior cannot be expressed as a pure-impure-pure composition, a pure-impure composition, an impure-pure composition, or an impure composition. You worked very hard to simplfy that code, and I believe an implicit claim of yours is that it cannot be simplified any further.In this case,
f'
would be the following function.As I defined it, this function is a pure-impure-pure-impure composition, which has length 4. Maybe in your jargon you would call this a pure/impure/pure/impure sandwich. My claim is that this function cannot be refactored into an impure/pure/impure sandwich.
Do you think that my claim is correct?
Tyson, thank you for your patience with me. Now I get it. As stated, your composition looks like a pure-impure-pure-impure composition, but unless you hard-code
privateKey
, you'll have to load that value, which is an impure operation. That would make it an impure-pure-impure-pure-impure composition.The decryption step itself is an impure-pure composition, assuming that we need to load keys, salts, etc. from persistent storage. You might also want to think of it as a 'mostly' pure function, since you could probably load decryption keys once when the application process starts, and keep them around for its entire lifetime.
It's a correct example of a more involved interaction model. Thank you for supplying it. Unfortunately, it's not one I can use for an article. Like other cross-cutting concerns like caching, logging, retry mechanisms, etcetera, security can be abstracted away as middleware. This implies that you'd have a middleware action that's implemented as an impure-pure-impure sandwich, and an application feature that's implemented as another impure-pure-impure sandwich. These two sandwiches are unrelated. A change to one of them is unlikely to trigger a change in the other. Thus, we can still base our application architecture on the notion of the impure-pure-impure sandwich.
I hope I've explained my demurral in a sensible way.
The are unrelated semantically. Syntatically, the whole application sandwich is the last piece of impure bread on the middleware sandwich. This reminds me of a thought I have had and also heard recently, which is that the structure of code is like a fractal.
Anyway, I am hearing you say that you want functions to have "one responsibility", to do "one thing", to change for "one reason". With that constraint satisfied, you are requesting an example of a funciton that is not an impure/pure/impure sandwich. I am up to that challenge. Here is another attempt.
Suppose our job is to implement a man-in-the-middle attack in the style of Schneier's Chess Grandmaster Problem in which Alice and Bob know that they are communicating with Malory while Malory simply repeats what she hears to the other person. Specifically, Alice is a client and Bob is a server. Mailory acts like a server to Alice and like a client to Bob. The funciton would look something like this.
This is a pure-impure-pure composition, which is different from an impure-pure-impure composition.
Tyson, thank you for writing. The way I understand it, we are to assume that both
convertIncoming
andconvertOutgoing
are complicated functions that require substantial testing to get right. Under that assumption, I think that you're right. This doesn't directly fit the impure-pure-impure sandwich architecture.It does, however, fit a simple function composition. As far as I can see, it's equivalent to something like this:
let malroyInTheMiddle = Async.fromResult >> Async.map convertIncoming >> Async.bind service >> Async.map convertOutgoing
I haven't tested it, but I'd imagine it to be something like that.
To nitpick, this isn't a pure-impure-pure composition, but rather an impure-pure-impure-pure-impure composition. The entry point of a system is always impure, as is the output.
Christer, I'd hoped that I'd already addressed some of your concerns in the article itself, but I may not have done a good enough job of it. Overall, given a question like
I tend to put emphasis on is it possible. Not that the rest of the question is unimportant, but it's more subjective. Perhaps you find that my article didn't answer your question, but I hope at least that I managed to establish that, yes, it's possible to refactor to an impure-pure-impure sandwich.Does it matter? I think it does, but that's subjective. I do think, though, that I can objectively say that my refactoring is functional, whereas passing impure functions as arguments isn't. Whether or not an architecture ought to be functional is, again, subjective. No-one says that it has to be. That's up to you.
As I wrote in my preliminary response, I'm not going to address your modification. I don't see that it matters. Even when you return an
Async<Result<_,_>>
you canmap
,bind
, ortraverse
over it. You may not be able to useAsyncResult.traverseBoth
, but you can derive specialisations likeAsyncResult.traverseOk
andAsyncResult.traverseError
.First, like you did, I find it illustrative to juxtapose the alternatives. I'm going to use the original example first:
In contrast, here's my refactoring:
It's true that my composition (
sut
) seems more involved than yours, but the overall trade-off looks good to me. In total, the code is simpler.In your evaluation, you make some claims that I'd like to specifically address. Most are reasonable, but I think a few require special attention:
Indeed. This should be listed as a pro, not a con. Whether or not it's worth it is a different discussion.As I wrote in the article:
(Emphasis from the original.) Isn't it always worth it to take away accidental complexity? No, it doesn't. It has a cyclomatic complexity of 1, exactly like the original humble object. True, but neither can the original humble object. According to which criterion? It has the same cyclomatic complexity, but I admit that more characters went into typing it. On the other hand, the composition juxtaposed with the actual function has far fewer characters than the original example.You also write that
I don't like the epithet non-standard. It's true that these functions aren't inFSharp.Core
, for reasons that aren't clear to me. In comparison, they're part of the standardbase
library in Haskell.There's nothing non-standard about functions like these. Like
map
andbind
, traversals and catamorphisms are universal abstractions. They exist independently of particular programming languages or library packages.I think that it's fair criticism that they may not be friendly to absolute beginners, but they're still fairly basic ideas that address real needs. The same can be said for the
asyncResult
computation expression that you've decided to use. It's also 'non-standard' only in the sense that it's not part ofFSharp.Core
, but otherwise standard in that it's just a stack of monads, and plenty of libraries supply that functionality. You can also write that computation expression yourself in a dozen lines of code.In the end, all of this is subjective. As I also wrote in my conclusion:
What I do, however, think is important to realise is that what I suggest is to learn a set of concepts once. Once you understand functors, monads, traversals etcetera, that's knowledge that applies to F#, Haskell, C#, JavaScript (I suppose) and so on.Personally, I find it a better investment of my time to learn a general concept once, and then work with trivial code, rather than having to learn, over and over again, how to deal with each new code base's accidental complexity.
Mark, thank you for getting back to me with a detailed response.
First, a general remark. I see that my comment might have been a bit "sharp around the edges” and phrased somewhat carelessly, giving the impression that I was not happy with your treatment of my example. I’d just like to clearly state that I am. You replied in your usual clear manner to exactly the question I posed, and seeing your process and solution was instructive for me.
We are all learning, all the time, and if I use a strong voice, that is primarily because strong opinions, weakly held often seems to be a fruitful way to drive discussion and learning.
With that in mind, allow me to address some of your remarks and possibly soften my previous comment.
Your article did indeed answer my question. My takeaway (then, not necessarily now after reading the rest of your comment) was that you managed to refactor to impure-pure-impure at the "expense” of making the non-pure part harder to understand. But as you say, that’s subjective, and your remarks on that later in your comment was a good point of reflection for me. I’ll get to that later.
I agree on all points.
I don’t agree 100% that it’s a completely fair comparison, since you’re leaving out the implementations of
AsyncOption.traverse
,AsyncResult.traverseBoth
, andAsyncResult.cata
. However, I get why you are doing it. These are generic utility functions for universal concepts that, as you say later in your comment, you “learn once”. In that respect, it’s fair to leave them out. My only issue with it is that since F# doesn’t have higher-kinded types, these utility functions have to be specific to the monads and monad stacks in use. I originally thought this made such functions less understandable and less useful, but after reading the rest of your comment, I’m not sure they are. More on that below.(Emphasis yours.) Just in case: “Evaluation” might have been a poor choice of words. I hope you did not take it to mean that I was a teacher grading a student’s test. This was not in any way intended personally (e.g. evaluating "your solution”). I was merely looking to sum up my subjective opinions about the refactoring.
I find it hard to say an unequivocal "yes” to such general statements. Ultimately it depends on the specific context and tradeoffs involved. If the context is “a codebase to be used for onboarding new F# devs” and the tradeoffs are “use generic helper functions to traverse bifunctors in a stack of monads”, then I’m not sure. (It may still be, but it’s certainly not a given.)
But generally, though I haven’t reflected deeply on this, I’m sure you’re right that it’s worthwhile to always take away accidental complexity.
You’re right. Thank you for the clarifying article on cyclomatic complexity.
That’s correct, but my point was that the original composition was trivial (just calling a “DI function” with the correct arguments/dependencies) and didn’t need to be tested, whereas the refactored composition does more and might warrant testing (at least to a larger degree than the original).
This raises an interesting point. It seems (subjectively to me based on what I’ve read) to be a general consensus that a function can be left untested (is “humble”, so to speak) as long as it consists of just generic helpers, like the refactored composition. That "if it compiles, it works”. This is not a general truth, since for some signatures there may exist several transformations from the input type to the output type, where the output value is different for the different transformations. I have come across such cases, and even had bugs because I used the wrong transformation. Which is why I said:
It is more complex in the sense that it doesn’t just call a function with the correct dependencies. The original composition is more or less immediately recognizable as correct. The refactored composition, as I said, required me to look at it more carefully to convince myself that it was correct. (I will grant that this is to some extent subjective, though.)
This is the primary point of reflection for me in your comment. While I frequently use monads and monad stacks (particularly
Async<Result<_,_>>
) and often write utility code to transform when needed (e.g.List.traverseResult
), I try to limit the number of such custom utility functions. Why? I’m not sure, actually. It may very well have to do with my work environment, where for a long time I have been the only F# dev and I don’t want to alienate the other .NET devs before they even get started with F#.In light of your comment, perhaps F# devs are doing others a disservice if we limit our use of important, general concepts like functors, monads, traversals etc.? Then again, there’s certainly a balance to be struck. I got started (and thrilled) with F# by reading F# for fun and profit and learning about algebraic types, the concise syntax, "railway-oriented programming” etc. If my first glimpse of F# had instead been
AsyncSeq.traverseAsyncResultOption
, then I might never have left the warm embrace of C#.I might check out FSharpPlus, which seems to make this kind of programming easier. I have previously steered away from that library because I deemed it “too complex” (c.f. my remarks about alienating coworkers), but it might be time to reconsider. If you have tried it, I would love to hear your thoughts on it in some form or another, though admittedly that isn’t directly related to the topic at hand.
Christer, don't worry about the tone of the debate. I'm not in the least offended or vexed. On the contrary, I find this a valuable discussion, and I'm glad that we're having it in a medium where it's also visible to other people.
I think that we're gravitating towards consensus. I definitely agree that the changes I suggest aren't beginner-friendly.
People sometimes ask me for advice on how to get started with functional programming, and I always tell .NET developers to start with F#. It's a friendly language that enables everyone to learn gradually. If you already know C# (or Visual Basic .NET) the only thing you need to learn about F# is some syntax. Then you can write object-oriented F#. As you learn new functional concepts, you can gradually change the way you write F# code. That's what I did.
I agree with your reservations about onboarding and beginner-friendliness. When that's a concern, I wouldn't write the F# code like I suggested either.
For a more sophisticated team, however, I feel that my suggestions are improvements that matter. I grant you that the composition seems more convoluted, but I consider the overall trade-off beneficial. In the terminology suggested by Rich Hickey, it may not be easier, bit it's simpler.
I have no experience with FSharpPlus or any similar libraries. I usually just add the monad stacks and functions to my code base on an as-needed basis. As we've seen here, such functions are mostly useful to compose other functions, so they rarely need to be exported as part of a code base's surface area.


Go as deep as you need to.
Each <n-view> element looks for child <n-view> elements and ensures they have its own URL in their path.
Check out the HTML declared to create this route.


Thinking: Abstract and Concrete
October 5, 2014
Applying Categories to My Mind
Gregorc Thinking Style
As you can see from the above graph, the Gregorc thinking style test categorizes me more in terms of what I'm not than what I am. My mind style is, to roughly equal extents, Concrete-Random, Abstract-Random, and Abstract-Sequential. I do not seem to have the attributes of a Concrete-Sequential thinker, at least per one questionairre.
What does it mean that I tend away from Concrete-Sequential thinking? I went to Dr. Gregorc's page about mind styles to learn more. I must say, I disagree with the notion that I am averse to or lack the following:
- an affinity for getting facts
- predictable situations
- applying ideas in pragmatic ways
While it's true that I'd rather not have every day be predictable, I generally am in favor of predictability when it comes to doing work. I also like to think that I prefer to operate on the basis of facts, and that I'd rather apply ideas than simply come up with them, write them down, and put them in a drawer. To not test an idea out in some practical way is to not fully generate the idea. As Milton wrote in his Areopagitica, "Let her and Falsehood grapple; who ever knew Truth put to the worse in a free and open encounter?" An idea requires a free and open encounter to become anything resembling a truth.
That said, the two entries on Abstract-Random and Concrete-Random do resonate with my experience. I would agree, I suppose, that I fit Gregorc's definition of a Random-Sequential thinker. One should be aware of one's flaws, so I think the cautionary tales are the lessons to take from this. To that end, here are tendencies that sound familiar, and that I should take note of:
- a dislike of formal reports
- the struggle to keep detailed records
- a preference to have options, as opposed to not
- a distase for dictatorial/authoritarian personalities
- aversion to the need to justify my feelings
- aversion to work in a restrictive environment
Some of those distastes feel worthy of note. I should account for my dislike of formal reports, and find a solution for generating such reports. I should realize that I need to strive to keep detailed records when the situation calls for it. Do I need to develop a taste for authoritarian personalities and restrictive environments? I don't see the point.
Fixed versus Growth Mindset
Dr. Carol Dweck, along with Dr. Gregorc, is has done prominent research on learning styles. Unlike Gregorc, Dweck outlines a more absolute difference between two ways of being. Dweck describes Fixed Mindsets and Growth Mindsets, and the latter is obviously preferable to the former.
Essentially, a Growth-minded person acknowledges their own limitations and, having done so, seeks to expands them. A Fixed-minded person perceives their capacity as set and unchangeable. It seems clear that our society encourages Growth-mindsets explicitly, but implicitly it may be that our culture of test-based and career-based identity thumps people into Fixed-mindsets I would suggest that at least two of the major cultural forces in world history--Christian Calvinism and Caste-based Hinduism--certainly lay rich foundations for a society of fixed-mindsets.
Luckily, our technologically-oriented world favors the growth-minded. I agree with Carol Dweck that this is plainly the better way to be.
Practical Ways Forward
Having reflected on the work Gregorc and Dweck, I think that a system of more organization and discipline will allow me to work better in DBC and onward. Actually, I think these blog posts are the perfect blend of routine, formal reporting, and practical wrestling with ideas that I need. In writing fiction, I constantly struggle to tend to my current projects daily, but I know how useful that is. Blogging provides an opportunity for that level of reflection and processing in my coding life.
explication with


Did you know that even the most conservative Americans leave ecological footprints twice the size of the global average footprint? The current way that Americans are living is unsustainable. Do you want to compare yourself to the average American? Click the "Let's Start!" button below.


PaymentServer
Integration Diagram
%% AUTOGENERATED CODE -- DO NOT EDIT! graph TD PaymentServer PaymentServer["PaymentServer"] --> Visa["Visa"] PaymentServer["PaymentServer"] --> MasterCard["MasterCard"] Dashboard["Dashboard"] --> PaymentServer["PaymentServer"] Website["Website"] --> PaymentServer["PaymentServer"]
Application Index
| Application Name | Method | Source Location |
|---|---|---|
| PaymentServer | Pay | /github.com/anz-bank/sysl-examples/demos/sizzle_restaurant/sizzle.sysl@master |
Type Index
| Application Name | Type Name | Source Location |
|---|---|---|
| PaymentServer | PaymentType | /github.com/anz-bank/sysl-examples/demos/sizzle_restaurant/sizzle.sysl@master |
Applications
Application PaymentServer
- This server handles all the payment related endpoints.
PaymentServer Pay
Sequence Diagram
%% AUTOGENERATED CODE -- DO NOT EDIT! sequenceDiagram ... ->> PaymentServer: Pay alt processor_type == "visa" PaymentServer ->> Visa: Pay Visa ->> Visa: ... else if processor_type == "mastercard" PaymentServer ->> MasterCard: POST /pay MasterCard -->> PaymentServer: error MasterCard -->> PaymentServer: ok <: SimpleObj else PaymentServer -->> ...: 500 < NotSupportedError end PaymentServer -->> ...: 200
Request types
No Request types
Response types
%% AUTOGENERATED CODE -- DO NOT EDIT! classDiagram
%% AUTOGENERATED CODE -- DO NOT EDIT! classDiagram
%% AUTOGENERATED CODE -- DO NOT EDIT! classDiagram
%% AUTOGENERATED CODE -- DO NOT EDIT! classDiagram
Types
PaymentServer.PaymentType
%% AUTOGENERATED CODE -- DO NOT EDIT! classDiagram
[Full Diagram](%% AUTOGENERATED CODE -- DO NOT EDIT!
classDiagram )


Changing things up a bit this time - because of All Saints' Day we are holding the meetup on the second Wednesday of November. Our speakers will be introducing some lesser known web development tools and their advantages over the the ones you use.
Marko will give us an overview of FuseBox's characteristics and advantages over the more popular options. To get you started with FuseBox and show how easy it is, we will look at the structure of a config file, it's built-in and third party plugins.
Duration: 20min + Q&A
In the world of blogging, hidden deep in the shadow of the mighty WordPress, a new contenders for the throne have emerged - the static site builders. In this lecture we'll have a look one of the them called Jekyll. In this live-coding session we'll build a simple website from scratch and show you how to use themes to build a GitHub page
Duration: 30min + Q&A


Sorted Trail Map
问题描述 :
Volunteers from the World Wildlife Foundation (WWF) have arrived in Springfield in a WWF truck.
They are collecting endangered animals living in the nearby Gump Forest, and are asking Lisa for help.
The WWF volunteers have given Lisa a map of the Gump Forest. The forest contains a number of clearings, and trails connecting the clearings. Different types of endangered animals live on each trail, no animals live in the clearings.
The WWF are hoping to collect some endangered animals from Gump Forest. But their trail map is too confusing, since clearings and animals are listed in no particular order. Lisa decides to help the WWF volunteers by making up a sorted trail map of Gump Forest.
They are collecting endangered animals living in the nearby Gump Forest, and are asking Lisa for help.
The WWF volunteers have given Lisa a map of the Gump Forest. The forest contains a number of clearings, and trails connecting the clearings. Different types of endangered animals live on each trail, no animals live in the clearings.
The WWF are hoping to collect some endangered animals from Gump Forest. But their trail map is too confusing, since clearings and animals are listed in no particular order. Lisa decides to help the WWF volunteers by making up a sorted trail map of Gump Forest.
输入:
Animals are given as words(lowercases). Clearings are given as numbers. There may be up to 500 clearings.
Clearing 0 is always the entrance to Gump Forest. The input is the unsorted Gump Forest trail map.
Each line describes a trail between two clearings as a pair of numbers, followed by a list of animals living on the trail.
Every test case ends with "-1 -1".
Clearing 0 is always the entrance to Gump Forest. The input is the unsorted Gump Forest trail map.
Each line describes a trail between two clearings as a pair of numbers, followed by a list of animals living on the trail.
Every test case ends with "-1 -1".
输出:
Animals are given as words(lowercases). Clearings are given as numbers. There may be up to 500 clearings.
Clearing 0 is always the entrance to Gump Forest. The input is the unsorted Gump Forest trail map.
Each line describes a trail between two clearings as a pair of numbers, followed by a list of animals living on the trail.
Every test case ends with "-1 -1".
Clearing 0 is always the entrance to Gump Forest. The input is the unsorted Gump Forest trail map.
Each line describes a trail between two clearings as a pair of numbers, followed by a list of animals living on the trail.
Every test case ends with "-1 -1".
样例输入:
0 1 puma 2 3 toad 1 2 frog -1 -1 1 0 puma lynx 2 0 toad 1 2 vole -1 -1
样例输出:
0 1 puma 1 2 frog 2 3 toad 0 1 lynx puma 0 2 toad 1 2 vole
http://acm.hit.edu.cn/hoj/problem/view?id=2597
列方程用对数求
#include <stdio.h> #include <math.h> int main() { double base, rate, target; int year; while (scanf("%lf %lf %lf", &base, &rate, &target) != EOF) { year=ceil(log(target / base) / log(1 + 0.01 * rate)); printf("%d\n",year); } return 0; }
解题转自：http://blog.csdn.net/epk_lee/article/details/8203929
(adsbygoogle = window.adsbygoogle || []).push({});
兵种文件在哪？
继续加油哦
秒！~
秒！~
红绯鱼：
牛逼牛逼
这排版…你都打开来看看改改
很好的题，还是能做出几道的，嘿嘿
大致看了下，算法的时间复杂度没有很本性的提升，算不上高效。
great!
一开始就规定不相邻节点颜色相同，可能得不到最优解。我想个类似的算法，也不确定是否总能得到最优解：先着一个点，随机挑一个相邻点，着第二色，继续随机选一个点，但必须至少有一个边和已着点相邻，着上不同色，当然尽量不增加新色，直到完成。我还找不到反例验证他的错误。。希望LZ也帮想想, 有想法欢迎来邮件。谢谢
递归还真是一门学问，学习了
很好的思路，可以借鉴
#include <cstdio>
#include <cstring>
const int MAXSIZE=256;
//char store[MAXSIZE];
char str1[MAXSIZE];
/*
void init(char *store) {
int i;
store['A']=’V', store['B']=’W',store['C']=’X',store['D']=’Y',store['E']=’Z';
for(i=’F';i<=’Z';++i) store =i-5;
}
*/
int main() {
//freopen("input.txt","r",stdin);
//init(store);
char *p;
while(fgets(str1,MAXSIZE,stdin) && strcmp(str1,"STARTn")==0) {
if(p=fgets(str1,MAXSIZE,stdin)) {
for(;*p;++p) {
//*p=store[*p]
if(*p<’A’ || *p>’Z') continue;
if(*p>’E') *p=*p-5;
else *p=*p+21;
}
printf("%s",str1);
}
fgets(str1,MAXSIZE,stdin);
}
return 0;
}
哇，算法有这么多呢！
有限自动机在ACM中是必须掌握的算法，实际上在面试当中几乎不可能让你单独的去实现这个算法，如果有题目要用到有限自动机来降低时间复杂度，那么这种面试题应该属于很难的级别了。


Swanalekha Malayalam Keyboard is based on Swanalekha, a transliteration based Malayalam input method developed by Santhosh Thottingal. For detailed information about Swanalekha input method, visit: https://swanalekha.smc.org.in


I see it over and over again.
Typically from the same people, and typically interjected into a post from the same few of my friends.
I'm talking about the Post Hijacker.
If you already know what I'm talking about then you probably are getting hot under the collar already. It's when someone injects a comment, into a comment stream, that has little or nothing to do with the OP.
Furthermore, said comment should really be a DM, since it quite literally has nothing to do with anyone else involved in the conversation, save perhaps the original poster, or, in some edge cases, a memeber of the commenting crew.
Here's an example:
Let's follow the conversation, and see if you can spot where the hijacker appears.
- First comment: obviously talking about someone in a picture.
- Second comment: obviously also talking about that someone in a picture.
- Third comment: a direct invitation to the original poster about getting together.
- Fourth comment: obviously also talking about the person in the picture.
If you said the hijacker appears in comment three, YOU WIN!!!
Post Hijackers:
Stop. Hijacking. Comment streams.
It's quite f*!$ing annoying.
In fact, I'll let you in on a little-known secret: Facebook makes an app specifically for what you are trying to do. Kindly use it, and quit polluting otherwise pointed discussions, regardless of how trivial they may be.
End rant.
--K


Student Management System
Fullname
Email Address
Gender
Select Gender
Male
Female
Course
Choose Course
UI/UX
Frontend Development
Backend Development
Software Engineering
Cloud Infrastructure
Info Security
Product Design
Ethical Hacking
Project Management
Register Now
Full Name
Email Address
Gender
Courses
Action


#include <light.h>
Inheritance diagram for Light:
Public Member Functions | |
| void | Draw () |
| This function does not any effect. | |
| void | UpdateTransform () |
| This function does not any effect. | |
| Matrix4fx | GetResultTransform () |
| Returns light source result transform matrix. | |
| Int | GetClassID () |
| Returns Light class id. | |
Static Public Member Functions | |
| static ObjRef< Light > | New () |
| Creates new Light. | |
| static ObjRef< Light > | New (Render3D *render_) |
| Creates new Light. | |
Public Attributes | |
| Int | type |
| Light's type. | |
| Color | color |
| Light's color. | |
| Color | specular |
| Light's specular color. | |
| Fixed | intensity |
| Light's intensity. | |
| Vector3fx | location |
| Light's location. | |
| Vector3fx | direction |
| Ligth's direction. | |
| Fixed | radius |
| Lght's radius. | |
| Bool | on |
| Is light turn ON. | |
Protected Member Functions | |
| Light () | |
| Default constructor. | |
| Light (Render3D *render_) | |
| Constructor with given render pointer value. | |
| ~Light () | |
| Destructor. |
|
|
Constructor with given render pointer value.
|
|
|
Returns Light class id.
Reimplemented from Basic3D. |
|
|
Returns light source result transform matrix.
Reimplemented from Basic3D. |
|
|
Creates new Light. Call this function instead constructor calling.
Reimplemented from Basic3D. |
|
|
Creates new Light. Call this function instead constructor calling.
Reimplemented from Basic3D. |


See: Description
| Interface | Description |
|---|---|
| EventsHandler |
Events receiver when a grammar is parsing an input.
|
| Grammar |
Base interface for defining grammars.
|
| Grammar.Combine.Flattenable |
For a rule that have components that may be flatten.
|
| Grammar.Combine.Simplifiable |
For a rule that can be replaced by its component if it has
just one, provided that it is not a grammar field.
|
| Grammar.Repeatable.Maximal |
For repeatable rules that must be repeated a maximal number of times.
|
| Grammar.Repeatable.Minimal |
For repeatable rules that must be repeated a minimal number of times.
|
| Handler |
Events receiver when a grammar is parsing an input
with rewind capabilities (mark, consume/cancel).
|
| Class | Description |
|---|---|
| EventsHandler.NumberValue |
A number as the token value.
|
| EventsHandler.RuleEnd |
Event fired when a rule ends ; indicates whether
the rule was fulfilled or not.
|
| EventsHandler.RuleEvent<R extends Grammar.Rule> |
When a rule or token is matched while parsing.
|
| EventsHandler.RuleStart |
Event fired when a rule starts.
|
| EventsHandler.StringValue |
A string as the token value.
|
| EventsHandler.TokenValue<T> |
A wrapper of a parsed value, the token that creates it,
and the position where the value was found when
available.
|
| Grammar.AtLeast |
Make a rule repeatable.
|
| Grammar.AtMost |
Make a rule repeatable.
|
| Grammar.Bounds |
Make a rule repeatable in bounds.
|
| Grammar.CharToken |
A character token, based on compositions of character ranges.
|
| Grammar.CharToken.Composed |
A token made of a several char ranges.
|
| Grammar.CharToken.Single |
A token made of a single char range.
|
| Grammar.Choice |
A choice rule ; when parsing, the first rule
that is fulfilled is selected.
|
| Grammar.Combine |
A rule skeleton for combining rules.
|
| Grammar.DropToken |
A token not transmitted to the event handler while parsing.
|
| Grammar.EnumToken<T> |
A token made from an enum class or a list of string values ;
the order of the enum values doesn’t matter ; the longest value
if available will be read from the input.
|
| Grammar.EnumValueToken |
An enum value token, just like a string, but with an enum value.
|
| Grammar.GrammarToken |
A token based on a grammar.
|
| Grammar.Number |
A number token.
|
| Grammar.Optional |
Make a rule optional.
|
| Grammar.Proxy |
Allow to separate a rule declaration
and its assignment.
|
| Grammar.Proxy.Deferred |
A proxy defined by an initializer.
|
| Grammar.Proxy.Named |
A proxy defined by its name.
|
| Grammar.Repeatable |
Base class for repeatable rules.
|
| Grammar.Rule |
A grammar is composed of rules that
can be tokens or so-called rules.
|
| Grammar.Sequence |
A sequence rule.
|
| Grammar.StringToken |
A string token.
|
| Grammar.Token |
When parsing, a token yield a
EventsHandler.TokenValue . |
| Grammar.TypedToken<T> |
A token based on rules.
|
| Grammar.TypedToken.Mapper<T> |
A token that collect its subrules to a list of items
that are mapped to a value.
|
| Grammar.TypedToken.Number |
A token that collect its subrules to a number.
|
| Grammar.TypedToken.String |
A token that collect its subrules to a single string.
|
| Grammar.TypedToken.TypedNumber<T extends Number> |
A token that collect its subrules to a number of a given type.
|
| Grammar.Wrapper |
A rule skeleton for composing rules.
|
| Grammar.ZeroOrMore |
Make a rule optional repeatable.
|
| Annotation Type | Description |
|---|---|
| Grammar.Drop |
The token value produced by the annotated token
won't be transmitted to the event handler while parsing.
|
| Grammar.Fragment |
Mark a token of a grammar that it is
a fragment of a rule token, or a rule
that is a fragment of a nested rule.
|
| Grammar.MainRule |
Mark the main rule of a grammar with this annotation.
|
| Grammar.Replace |
Replace a rule/token field when extending
a grammar.
|
| Grammar.Skip |
Indicates the characters to skip (typically, some
whitespaces) before and after parsing a token.
|
Copyright © 2020 Alternet. All rights reserved.