このページは http://www.slideshare.net/FaisalWaris/unraveling-the-mystery-of-monads の内容を掲載しています。

掲載を希望されないスライド著者の方は、こちらよりご連絡下さい。

- Unraveling the Mystery

of Monads

Developing an intuitive understanding of monads

(without resorting to Category Theory) - About Me

• Faisal Waris

• IT Career started in the 90’s with Smalltalk

• A wide variety of experience in a host technologies

and industries

• Blog: http://fwaris.wordpress.com

• Currently consulting with a major auto manufacturer

in Michigan

• Working on emerging technologies research in Analytics

and BI

• Pursing Post Graduate Studies - Language Background

• Smalltalk (90’s) [also some C++]

• OO + Functional

• Dynamic Typing

• Meta-programming

• Refection

• Java, C# (2001-2010)

• Was never real y satisfied (although C# has made big strides)

• Stil missed Smal talk

• F# (2010+)

• Seemed to hit the spot

• Succinct and expressive

• Almost al of the needed features ; Innovative new features such as Type Providers

• Statical y Typed but with Type Inference feels like a Dynamical y Typed language

• ‘Functional-first’

• Monads - Monads: Motivating Example

• Imagine a

set of AJAX

user id

calls with

Get

the shown

profile id,

Profile

last login date

profile id

dependency

graph

Get

Get

Events

paral el execution

Messages

profile, events, messages

UI

Processing - JQuery Serial Version

$.ajax({

url: "profile/" + user_id,

type: 'POST',

success: function (data, textStatus, jqXHR) {

var profile = jQuery.parseJSON(jqXHR.responseText);

$.ajax({

url: "events/" + profile.id,

type: 'POST',

success: function (data, textStatus, jqXHR) {

This is a serial

var events = jQuery.parseJSON(jqXHR.responseText);

version.

$.ajax({

url: "messages?profile_id=" + profile.id + "&last_login=" + profile.last_login,

type: 'POST',

success: function (data, textStatus, jqXHR) {

The parallel version

var messages = jQuery.parseJSON(jqXHR.responseText);

was too daunting for

doUIProcessing(profile, events, messages);

me to even attempt!

},

error: function (data, textStatus, jqXHR) { notify(textStatus); }

});

},

error: function (data, textStatus, jqXHR) { notify(textStatus); }

});

},

error: function (data, textStatus, jqXHR) { notify(textStatus); }

}); - F# + WebSharper - Async Monad

Parallel Version

async {

try

let! profile = getProfile userid

let! events,messages =

getEvents profile.Id profile.LastLogin <||> getMessages profile.Id

doUIProcessing (profile, events, messages)

with

| ex -> notify(ex.Message)

} - Part I – Monad Basics
- How to Grok Monads

• First forget almost everything you know about ‘normal’ programming

• Forget

• Variables and Assignments

• Statements

• Loops

• …

• Now go back to the basics

• … the very basics

• What does it mean to compute? - Equivalent Models of Computation ©

1940’s

• Turing Machines

• Developed by Alan Turing

• Computing with machines

•

Lambda Calculus

• Alonzo Church

There other models

of computations

• Computing with mathematics

such as Recursive

Functions,

Relational, …

The concept of algorithm was first introduced

All function programming languages trace their roots

to Lambda Calculus - Lambda Calculus

• Lambda Calculus is very simple – there is only one thing cal ed ‘lambda term’

• Lambda Term

Bottom Line:

• Variable: x, a variable, is a lambda term

Any computable algorithm

• Lambda Abstraction: If t is a lambda term then λx.t is a lambda term

can be implemented using

• Equivalent to defining a function

the simple definitions and

• Application : if t and s are lambda terms then ts is a lambda term

rules of Lambda Calculus.

• Equivalent to calling a function t with input value s

• Notes

Your ‘program’ is a single

lambda expression –

• A ‘variable’ is an identifier bound to the input value (not a memory slot)

composed of other terms.

• There are no named functions

Reducing the lambda term is

• Functions only accept a single value but ‘currying’ is used for multiple input parameters

equivalent running the

• Functions are Higher Order, i.e. can accept other functions as input parameters and return functions program

as values

• Recursion is handled via fixed-point combinators such as the Y-combinator

• Arguments are not evaluated before binding to lambda expression – lazy evaluation - Function Composition

The Essence of ‘Functional’ Programming

• A key to understanding monads

• For the OO people among us

There are no

• Your program is essentially one large function composed of smal er functions

‘statements’ that you

• Functional programming is based on Lambda Calculus

can sequence one

• We learned function composition in high school:

after the other –

• f (x) : int int

everything must be

• g (x) : int int

done via function

• (f ∙ g) (x) : int

composition

int

• Equivalent to f (g (x))

• Think of (f ∙g) as a new function built from the composition of functions

f and g. - Function Composition in Functional

Programming Languages

• In modern functional programming…

• One does not always get the sense that the entire program is one large

function

• However function composition is used very often

• Especially in Haskel

• Function Composition Operators

• Haskell: . (period)

• F#: >>

• F# has other ‘composition’ operators such as |> for pipelining - Composition Example in F# - Word

Count

o p en System

o p en System .IO

let sp litLine (l:string) = l.Sp lit([|' '; '.'|], Strin gSp litO p tions.R em o veEm p tyEntries)

//string seq -> (string*int) seq

let w o rd C o u n t =

Seq .m ap sp litLine

> > Seq .collect (fun xs -> xs)

> > Seq .m ap (fun w -> w .ToLow er())

> > Seq .countB y (fun w -> w )

> > Seq .sortB y (fun (_,c) -> -c)

let file = @ "C :\ U sers\ ...\ So m eFile.txt"

file |> File.R ead Lines |> w o rd C ou nt - Word Count Output

("the", 34253); ("and", 21394); ("to", 16536); ("of", 14920); ("a", 10418);

("he", 9411); ("in", 8789); ("his", 7941); ("that", 7485); ("was", 7235);

("with", 5659); ("had", 5338); ("not", 4510); ("at", 4502); ("it", 4389);

("her", 4348); ("as", 3908); ("on", 3769); ("but", 3626); ("him", 3612);

("for", 3412); ("she", 3259); ("i", 3234); ("is", 3064); ("you", 2860);

("from", 2666); ("all", 2566); ("said", 2536); ("by", 2368);

("were", 2368); ("be", 2346); (""", 2281); ("they", 2066); ("who", 1941);

("have", 1937); ("what", 1937); ("which", 1927); ("one", 1908);

("this", 1886); ("prince", 1748); ("so", 1661); ("an", 1614); ("or", 1554);

("pierre", 1483);… - What About Side Effects?

• So far we have looked at pure functions – no side effects

• In the real world we need side effects

• otherwise the whole exercise does not seem very interesting

• How to combine pure functions with side effects?

• IO

Its really about controlling

or managing side effects

• UI

• State

“… being explicit about

• Exceptions

side effects” – Erik Meijer

• Continuations (asynchronous computations)

(Not OO-style rampant

• …

mutation) - Eugenio Moggi

• Eugenio Moggi is a professor of Computer

Science at the University of Genoa, Italy.

• He first described the general use of

monads (from Category Theory) to

structure programs for side effects

• Moggi’s work was about understanding

computation semantics to prove

equivalence of programs (© 1991)

• “Notions of Computation and Monads”,

Information and Computation (‘93) - Phillip Wadler

• Professor of Computer Science at University of Edinburgh

• First described the use of monads to structure functional code – in

the context of pure functional languages, especially to manage side

effects

• “Monads for Functional Programming” University of Glasgow (‘92)

• Note

• Pure languages like Haskel need monads for IO and state management

• Impure functional languages (Scala, F#, Clojure, etc.) don’t need monads

• Monads are useful even in impure functional languages as a way to

structure code more cleanly - My Intuition about Monads

• Monads are a way of writing code at a higher level of abstraction

• In particular monads offer a clean way to managing ‘things on the side’

• So that your main code is free of clutter

• ‘things on the side’ is purposely left vague as it could be a vast variety of things

• Examples later

• Seen in this way monads are like Aspect Oriented Programming (AOP)

• However AOP is uncontrolled

• You can’t reason about your program as you don’t know what is happening under the covers

• Monads gives you similar benefit but in a precise and controlled way

• …explicit and part of the type system - Back to Function Composition

• Say you have a computation composed of three functions, f, g & h:

• (f g

∙ h

∙ ) (x) : int int

• You want to manage ‘something on the side’

• Maybe you want to log something to the console each time a function is cal ed

• Or the functions need to access some global state - which may change as the

computation progresses

• And you don’t what the side activity to be too intrusive

• Wel , with ‘normal’ function composition you can’t real y do much - Enter the Monad

Don’t think of M as a Class.

• What if you wrapped the input value into something

It could any type –

• Instead of just int you now have M int

including a function type

• Read M int as Monad of int - a new type

• Your input is now a monadic value of type M int instead of just a

You need to

simple integer

implement the kind

• This opens up some possibilities

of monad you want

• Because the type M is what you define

• It is part of the monad implementation

(or use an available

• along with some functions which are described next

implementation)

• However f, g & h take int as an input parameter not M int

• The type signatures are not compatible

Think of monad as a

• What to do?

context around the data

• Well, managing all of this gets the ball rolling…

that flows between

functions - Three Parts of Monad Implementation:

Monadic Type, Return & Bind

• Monadic Type –

• In typed functional languages it’s the type of the monadic value

• Note type does not mean Class, it could be a function type (there are other types)

• In dynamically typed languages such as Clojure this is usually a function

• Type: M

All three have to be

consistent with

• Return – is a function that creates a monadic value from an ‘ordinary’ value

each other

• “return” is a cause of confusion because of its meaning in other languages

• Think of “…return me a monadic value”

• Also called “unit” in Haskel

• Type Signature: ’a M ‘a

• Bind – is a function that packages a monadic value with function that

accepts an ordinary value and produces another monadic value

• Type Signature: M ’a (‘a M ‘b) M ‘b - Understanding the Bind Function

Signature

• Type Signature: M ’a (‘a M ‘b) M ‘b

• There are 3 terms:

Term

Description

M ‘a

Monadic value for an ordinary value of type ‘a

(‘a M ‘b)

A function that takes an ordinary value of type ‘a and returns a

monadic value of type ‘b

M ‘b

The return type of the bind function, Monadic value of type ‘b

• The bind function takes two parameters, M a’ & a function with signature (‘a

M ‘b) and returns M ‘b - A Bit About Currying / Partial

Application

• let add x y = x + y

• A function that takes two numbers and returns their sum

• Now cal this function as fol ows:

• let add7 = add 7

• Note that we have not supplied the 2nd parameter to add

• What is the value of add7?

• add7 is a new function that accepts a single number and returns 7 + the number

• The function add7 was created by partial application of add to 7

• Add and Add7 Function Signatures

• add: int int int

• add7: int int - Intuition about Return and Bind

• Return is easy – its just packaging an ordinary value into a

monadic value

• Bind [M ’a (‘a M ‘b) M ‘b ] works as follows:

Return and Bind are

• Take out the ordinary value from the monadic value (1st argument:

invoked as flow

M ‘a)

progresses through

• Invoke the function (2nd argument: a’ M ‘b)

composed functions;

• Return the result (M’ b)

they provide the

• The implementations of Return and Bind – corresponding to interjection points for

the monad – control:

your code to do monad

• how to package ordinary values into monadic values

specific processing

• How to extract ordinary value from monadic values - Back Again to Function Composition

• Recall that we have a computation composed of three functions, f, g

& h:

• (f ∙g ∙h) (x) : int int

• Where each f, g & h have the signature int int

• Assume we have a monad implementation:

• Type: M ‘a

• Return: ‘a M ‘a

• Bind: M ‘a (‘a M ‘b) M ‘b

• Now we want to ‘monadify’ the computation - Modifying Functions to Work with

Monads

• To work with monads, we have to modify the function signatures of f,

g & h:

• From int int

• To int M int

• Where the generic type parameter ‘a is bound to int

• Let f’, g’, h’ be corresponding monadic functions with type signatures

• int M int

• Note that the new functions are not composable directly anymore

• The functions’ return type M int is not compatible with the input type int - Composing Monadic Functions

• The normal function bind operator does not apply with monadic

functions

• Recall that “ . “ is for Haskell and “ >> “ is the F# equivalent

• A new monadic bind infix operator is needed

• The monadic bind operator in Haskell is “ >>= “

• Given such an operator our new composed function is:

• let fgh’ a = (Return a) >>= f’ >>= g’ >>= h’) - Now An Example (finally!)

• Lets first define some functions…

let f i = i * 4

let g i = i + 2

let h i = i % 42

• And their composition…

let fgh = f >> g >> h

• And cal the composed function…

fgh 24

• Which results in…

val it : int = 14 - Count Monad

• A monad to count module CountMonad =

the number

functions invoked type Count<'a> = 'a*int //pair of some type and an int

during the

evaluation of a

computation

let m_return (a:'a) : Count<'a> = a,0

let m_bind (c:Count<'a>) (f:'a->Count<'b>) : Count<'b>=

let input,count = c

The bind

let output,_ = f input

function is

Note the monad

assigned to an

output, count + 1

implementation specifies the 3

infix monadic

requirements, Monadic Type,

bind operator

Return & Bind

let (>>=) = m_bind - Count Monad: Monad Type

• type Count<‘a> = ‘a*int

• The monadic value is a pair of the ‘ordinary’ value and an integer

• ‘a*int is the type signature for a 2-tuple, F# - e.g. (“a”, 1) : string * int

• In this case the ordinary value can be of any type, denoted by the

generic type parameter ‘a

• The integer part is the count that we want to maintain as we thread

the monad through the computation - Count Monad: Return Function

let m_return (a:'a) : Count<'a> = a,0

• The Return function simply converts an ordinary value to a monadic

value

• A pair or 2-tuple of the given value and an integer

• The initial count is set to 0 - Count Monad: Bind Function

let m_bind (c:Count<'a>) (f:'a->Count<'b>) : Count<'b> =

let input,count = c

let output,_ = f input

output, count + 1

• The type signature is:

• Count<‘a> (‘a Count<‘b>) Count<‘b>

• As required for the bind function

• It is the heart of the monad:

• Receives a monad from the previous invocation

• It extracts the ordinary value and the count (let input, count = c)

• Invokes the bound function (f) with the extracted value (input) and gets a monad as a result

• It extract the ordinary value from the resulting monad (let output,_ = f input)

• Returns a new monad with the count incremented (output, count + 1)

• Each time the Bind function is invoked the count is incremented and passed along - Count Monad: Bind Operator

let (>>=) = m_bind

• The infix bind operator is technically not necessary because we can

use the Bind function

• However it is really desirable because the composed code looks much

cleaner - Count Monad: Function Modification

• Now we need to modify our functions slightly to work with the Count

monad

• Existing functions

let f i = i * 4

let g i = i + 2

let h i = i % 42

• Now we create monadic versions of our functions:

let f' = f >> m_return

The monadic functions are created by composing

let g' = g >> m_return

our existing functions with the helper function.

The new functions have the type signature:

let h' = h >> m_return

int -> Count<int> - Count Monad: Composition

• Original composition

let fgh = f >> g >> h

• The monadic version

let fgh’ a = m_return a >>= f’ >>= g’ >>= h’

The monadic version is not exactly

• We invoke it as follows…

the same as the ‘ordinary’ version

fgh' 24

but feels very close.

• And get the result…

Once the monad implementation is

done and out the way, the code

val it : Count<int> = (14, 3)

flow feels very natural. - Intuition about Monadic Bind

• Consider the monadic composition

• let fgh’ a = m_return a >>= f’ >>= g’ >>= h’

• By gluing the monadic functions together with the bind operator we

can insert our own logic between successive invocations of the

functions

• In this sense the “ >>= “ operator can be seen as a counterpart to the

semi-colon (“ ; “) statement delimiter in languages such as Java and

C#

• Hence we sometimes get a sense that implementing monads is like overriding

the semi-colon - Trace Monad

• Instead of counting the number of function calls,

module TraceMonad =

we want to get a list of functions that were

type Trace<'a> = 'a*(string list)

invoked

•

Here is another monad implementation for the

trace functionality

let m_return a = a,[]

let m_bind a f =

let input,l1 = a

let output,l2 = f input

output, l1 @ l2

let (>>=) = m_bind - Using the Trace Monad

• Existing functions

let f i = i * 4

let g i = i + 2

let h i = i % 42

• We define a different helper function to help ‘monadify’ our functions:

let helper_return fname (a:'a) = a,[fname]

• Now we create monadic versions of our functions:

let f' = f >> helper_return "f"

let g' = g >> helper_return "g"

We can swap the

let h' = h >> helper_return "h“

monad

• The final monadic composition is the same as before:

implementations

let fgh’ a = m_return a >>= f’ >>= g’ >>= h’

with very little

fgh' 24

change to our

Result: val it : int * string list = (14, ["f"; "g"; "h"])

application code - Monad Laws

• Monad implementations should obey these laws

• For proper function composition

//left unit

(m_return 0) >>= (fun b -> f' b) = f' 0

//right unit

(m_return 10) >>= (fun b -> m_return b) = (m_return 10)

//associative

(m_return 2000) >>= (fun a -> f' a >>= g') = ((m_return 2000 >>= f') >>= g') - Part II – Monad Applications and

Examples - Monads in Real Life

• Examples of monad use in the F# language

• Async monad

• Sequence Expressions

• Query Expressions

• Formlets monad - WebSharper and F#

• Haskell Monads

• IO

• State

• Reader / Writer

• List

• …

• (not elaborated in this presentation) - About F#

• F# is a hybrid functional – OO language for the .Net platform

• It was developed at Microsoft Research

• Principal designer: Don Syme

• It was most directly influenced by OCaml but also contains Haskell influences

• Supports

• First class functions; pattern matching; type inference; meta-programming

(quotations); OO; actors; .Net integration; Computation Expressions (monads); Active

Patterns; Type Providers

• Available as part of Visual Studio (syntax highlighting, Intel isense, etc.)

• Mono versions of F# can run on Linux platforms (including Android) - F# Computation Expressions

• Like Haskell’s “ Do “ notation, F# provides an alternative syntax for

composing monadic computations

• The alternative syntax is easier to use in many scenarios

• The built-in monads in F# such as Async<‘a> use this syntax

• Computation Expressions have more than Bind and Return functions;

the also have

• Try-With / Try-Finally / While / For / Yield, …

• You have to implement a ‘builder’ type to enable this syntax in F#

code for a custom monad - Converting the Trace Monad to Enable

Computation Expression Syntax

type TraceBuilder() =

The “m_bind” and

member x.Bind (comp, func) = m_bind comp func

“m_return” functions

member x.Return (value) = m_return value

are from the

TraceMonad defined

“let!” is the same as

the Bind operator

let trace = new TraceBuilder()

earlier

and “return” is the

----------------------------------------------------------------------

Return function

let fgh2 a =

trace {

The compiler

let! p1 = f' a

le

let t ffgh’

gh’ a

a == m

m__rreettur

ur n

n aa >>>>== f f’ ’ >>>>== gg’ ’ >>>>== h’

h’

converts this syntax

let! p2 = g' p1

into the syntax we

let! p3 = h' p2

used earlier

return p3

}

fgh2 24 - Utility of Computation Expression

Syntax

Use prior results downstream

Try-Catch / Try-Final y

Intermix monad with regular code

compExp1 {

compExp2 {

compExp3 {

let! p1 = f' a

try

let! p1 = f' a

let! p2 = g' p1

let! p1 = f' a

if p1 > 10 then

let! p3 = h' p1 p2

let! p2 = g' p1

let! p2 = g' p1

return p3

let! p3 = h' p3

let! p3 = h' p3

}

return p3

return p3

with

else

| ex -> return <default value>

return p1

}

}

The compiler still converts these to function composition

but code is cleaner as we avoid writing nested lambda expressions - Traditional Asynchronous Computation Approaches

– Assume Invocation of a Remote Service

Future

Callback

•

A cal to an asynchronous service is made with an extra parameter – a callback

•

The way a callback is supplied is implementation specific; it can be a:

• lambda expression

• a method name

•

A cal to an asynchronous service returns immediately with a Future object.

• an event handler

The Future wil eventual y contain the response from the cal . The cal ing

thread can pol the Future and proceed further when the response is

available.

• or a ‘closure’ in the form of an

inline interface implementation

(such as Runnable in Java).

•

The calling thread usually completes without waiting for a response. When the

response arrives, the callback method is invoked and further processing is

handled in the callback, typically on a different thread. - Sequencing Async. Calls

• Assume 3 synchronous service calls with sequential dependency

let s1 = Service1 ()

let s2 = Service2 (s1)

let s3 = Service3 (s1,s2)

• Downstream service cal s need results from previous cal s

• Converting the service cal s to asynchronous yields the fol owing method

signatures:

Service1(callbackHandler<s1>)

Service2(s1, callbackHandler<s2>)

Service3(s1,s2,callbackHandler<s3>)

• The response is now returned in the callback handler which gets invoked on a separate

thread - Sequencing Async. Calls: Issue Nested

Lambdas

Service1(

fun s1 ->

Service2(s1,

fun s2 ->

Service3(s1,s2,

fun s3 -> … <handle final result>…))) - Sequencing Async. Calls: F# Async

Monad

async {

F# has utility methods to

let! s1 = Service1Async()

convert any .Net asynchronous

method to an Async monad:

let! s2 = Service2Async(s1)

web service, database, HTTP,

TCP, etc.

let! s3 = Service3Async(s1, s2)

return s3

}

Callback for

Computation Expression

Service2(…) call

allow asynchronous code

to look like synchronous

code! - Parallel Async. Calls: Fork-Join

[

AsyncHttp "http://www.live.com"

AsyncHttp "http://www.google.com"

let AsyncHttp (url:string) =

AsyncHttp "http://maps.live.com"

async {

AsyncHttp "http://maps.google.com"

// create the web request object

]

let req = WebRequest.Create(url)

|> Async.Parallel

// get the response, asynchronously

|> Async.Run

let! rsp = req.GetResponseAsync()

//returns a list of html strings

// read html string

use stream = rsp.GetResponseStream()

use reader = new System.IO.StreamReader(stream)

return reader.ReadToEnd()

Source: Don Syme’s Blog

} - A Computation Expression for the

Fibonacci Sequence

let infinteFibonacci =

seq{ yield 0; yield 1

let rec fib n1 n2 = seq {yield n1+n2; yield! fib n2 (n1+n2)}

yield! fib 0 1}

//get the first 1000 Fibonacci values

infinteFibonacci |> Seq.take 1000

//0,1,1,2,3,5,8,…

Sequence Expressions “ seq { … } “ uses F# Computation Expression support

under the covers in a lazy evaluation style. - F# Type Providers & Query

Computation Expression (LINQ)

F# Type Providers extract

type DB = SqlEntityConnection<ConnectionString=“ … database connection string … “>

and present type

let context = EntityConnection.GetDataContext()

information from remote

sources (database, web

// join two tables

service, oData,…) at

query {

for course in context.Courses do

coding time

join dept in context.Departments on (course.DepartmentID = dept.DepartmentID)

select (course, dept.Name)

}

F# 3.0 enhancements

This computation expression uses .Net LINQ

allow custom

(Language Integrated Query) under-the-covers to

keywords (e.g. join,

generate and execute SQL on the database – this

select) to be defined

expression is typed checked as normal F#

for use in computation

expressions - Dynamic User Interfaces:

WebSharper™

• By ‘dynamic’ we mean that the user interface re-configures itself based

on the choices made by the user (example next)

• About WebSharper

• F# and Visual Studio Extension for building Rich Web / Mobile Applications

• Integrates with many JavaScript Frameworks

• JQuery, JQueryMobile, SenchaTouch, etc.

• Combinators for HTML / HTML5

• Translates F# code to JavaScript

• Including Async computation expressions

• Leverages built-in F# meta-programming

• Uses Computation Expressions for Dynamic UI - Insurance Policy Application UI

(Data Collection Decision Tree)

Age affects Life

Insurance data

collected - Insurance Policy Application UI

Computation Expression

Formlet.Do

All of the UI can be rendered

{

on a single page which is

let! applicant = ApplicantForm

dynamically re-configured

based on age and policy type

let! policy = policyForm

choices made by the user

let! insurance =

(see demo)

match policy with

| "h" -> HomeChoice

| "a" -> AutoChoice

| _ ->

if applicant.Age < 50 then LifeYoungChoice

Monadic code is high level,

else LifeOlderChoice

very readable and

return insurance

intention-preserving!

} - Monads Summary

• A construct for writing code at a higher level of abstraction

• Applies to functional programming because it uses function

composition

• All examples presented used monadic bind function composition

• Monads are required to enable side-effects in pure functional

languages; e.g. Haskell

• Monads are not required in ‘impure’ languages but can greatly

facilitate certain kinds of scenarios:

• Examples, asynchronous & parallel computations; sequence expressions;

query expressions; dynamic user interfaces - Q & A

Source:

Aino Corry