Избегание сопоставления с вложенным шаблоном (возможно, с монадой) - PullRequest
10 голосов
/ 02 ноября 2010

Как можно переписать соответствие вложенного шаблона, например, в следующем примере, чтобы None было указано только один раз? Я думаю Монада Может решить эту проблему. Есть ли что-то похожее в базовой библиотеке F #? Или есть альтернативный подход?

match a with
| Some b ->
    let c = b.SomeProperty
    match c with
    | Some d ->
        let e = d.SomeProperty
        //and so on...
    | None -> ()
| None -> ()

Ответы [ 4 ]

12 голосов
/ 02 ноября 2010

Вы можете решить эту проблему, используя встроенные возможности: Option.bind

type A = 
    member this.X : B option = Unchecked.defaultof<_>
and B =
    member this.Y : С option = Unchecked.defaultof<_>
and С =
    member this.Z : string option = Unchecked.defaultof<_>


let a : A = Unchecked.defaultof<_>
let v = 
    match 
        a.X 
        |> Option.bind (fun v -> v.Y) 
        |> Option.bind (fun v -> v.Z) with
    | Some s -> s
    | None -> "<none>"  

Честно говоря, я сомневаюсь, что здесь представлена ​​полноценная реализация «возможно» (с помощью выражений вычислений)может сократить код.

РЕДАКТИРОВАТЬ : Режим сна - включен

Я думаю, что версия с Option.bind может быть уменьшена, если F # имеетболее легкий синтаксис для особого случая: лямбда-выражение, ссылающееся на некоторый член аргумента:

"123" |> fun s -> s.Length // current version
"123" |> #.Length // hypothetical syntax

Вот как пример можно переписать в Nemerle, который уже имеет такие возможности:

using System;
using Nemerle.Utility; // for Accessor macro : generates property for given field

variant Option[T]
{
    | Some {value : T}
    | None
}

module OptionExtensions
{
    public Bind[T, U](this o : Option[T], f : T -> Option[U]) : Option[U]
    {
        match(o)
        {
            | Option.Some(value) => f(value)
            | Option.None => Option.None()
        }
    }
}

[Record] // Record macro: checks existing fields and creates constructor for its initialization  
class A
{   
    [Accessor]
    value : Option[A];
}

def print(_)
{
    // shortened syntax for functions with body -> match over arguments
    | Option.Some(_) => Console.WriteLine("value");
    | Option.None => Console.WriteLine("none");
}

def x = A(Option.Some(A(Option.Some(A(Option.None())))));
print(x.Value.Bind(_.Value)); // "value"
print(x.Value.Bind(_.Value).Bind(_.Value)); // "none"
5 голосов
/ 02 ноября 2010

Мне нравится ответ Desco;всегда следует отдавать предпочтение встроенным конструкциям.Но, FWIW, вот как может выглядеть версия рабочего процесса (если я правильно понимаю проблему):

type CE () =

  member this.Bind (v,f) =
    match v with
      | Some(x) -> f x
      | None -> None

  member this.Return v = v


type A (p:A option) =

  member this.P 
    with get() = p


let f (aIn:A option) = CE () {
  let! a = aIn 
  let! b = a.P 
  let! c = b.P 
  return c.P }

let x = f (Some(A(None)))

let y = f (Some(A(Some(A(Some(A(Some(A(None)))))))))

printfn "Your breakpoint here."
1 голос
/ 02 ноября 2010

Я не предлагаю этого, но вы также можете решить это с помощью обработки исключений:

try
    <code that just keeps dotting into option.Value with impunity>
with
    | :? System.NullReferenceException -> "None"

Я просто хотел указать на грубую эквивалентность обработки исключений для монад Возможно или Любой, или Option.bind.Обычно предпочитают один из них бросать и ловить исключения.

0 голосов
/ 16 января 2014

Использование Option.maybe из FSharpx:

open FSharpx
type Pet = { Name: string; PreviousOwner: option<string> }
type Person = { Name: string; Pet: option<Pet> }

let pers = { Name = "Bob"; Pet = Some {Name = "Mr Burns"; PreviousOwner = Some "Susan"} }

Option.maybe {
    let! pet = pers.Pet
    let! prevOwner = pet.PreviousOwner 
    do printfn "%s was the previous owner of %s." prevOwner pet.Name
}

Вывод:

Susan was the previous owner of Mr Burns.

Но, например, вместо этого человека просто нет вывода:

let pers = { Name = "Bob"; Pet = None }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...