2

Foo.yネストされたデータ (以下の例の内部)にアクセスしようとしていますが、頭に浮かぶ内部Barをアンラップする簡単な方法は機能しません。しかし、それを正しくアンラップする方法は?FooBar

ここに私のデータ:

module Foo where

import Prelude

data Foo = Foo { y :: Int }

data Bar = Bar { x   :: Int
               , foo :: Foo }

次の (もちろん) はコンパイルされません。エラーはCould not match type { y :: Int } with type Foo— のようBarに、Foo最初に展開する必要があります。

fn1 :: Bar -> Int
fn1 (Bar { x, foo }) = x + foo.y

したがって、私は次のことを期待していますが、残念ながら、コンパイラは「いいえ」と言います (Fooコンストラクターの括弧は役に立ちません)。

fn2 :: Bar -> Int
fn2 (Bar { x, Foo { y } }) = x + y

fn3 :: Bar -> Int
fn3 (Bar { x, Foo f }) = x + f.y

次の例では、ヘルパー関数を使用してアンラップを実行していますが、もっと良い方法が必要です。

getY (Foo foo) = foo -- helper function

fn4 :: Bar -> Int
fn4 (Bar { x, foo }) = let foo2 = getY foo in
                       x + foo2.y

では、ネストされた「アンラップ」を行うにはどうすればよいでしょうか?

[編集]

1〜2時間試してみた後、これを思いつきました。これはうまくいきます:

fn5 :: Bar -> Int
fn5 (Bar { x, foo = (Foo f) }) = x + f.y

これは慣用的な方法ですか?なぜ仕事をしないfn2fn3ですか?

4

1 に答える 1

3

関数fn2およびfn3は機能しません。これは、参照しているレコード フィールド ( foo ) がコンパイラに認識されないためです。レコード フィールドを名前で参照する必要があります。

関数fn4は完全に優れたソリューションです (命名はかなり混乱していますが、getYは実際にはy値ではなく、 Fooコンストラクター内でラップされたレコードを返します)。

私が知る限り、fn5が最短のソリューションです。私は個人的にヘルパー関数を好みます(4番目の例のように):

getY :: Foo -> Int
getY (Foo rec) = rec.y

fn6 :: Bar -> Int
fn6 (Bar { x, foo }) = x + getY foo
于 2016-03-05T18:45:10.117 に答える