4

Scala でモナドをプログラミングする方法を学ぼうとして、いくつかの問題が発生しました

簡単なコードサンプルを考えると

import Control.Monad

newtype LJ a = LJ { session :: a }

instance Monad LJ where
  return s = LJ s
  (>>=) m f = f ( session m )

instance Functor LJ where
  fmap f m = LJ . f $ session m

type SimpleLJ = LJ String

auth :: String -> String -> SimpleLJ
auth = undefined

readFeed :: String -> SimpleLJ
readFeed = undefined

closeFeed :: String -> SimpleLJ
closeFeed = undefined

proceed = auth "123" "456" >>= readFeed >>= closeFeed

同じことを (scalaz ではなく) Scala で書くにはどうすればよいですか? 私が学んだ限りでは、scala で map/flatMap メソッドを実装するだけで十分ですが、ここで return とは何ですか? forステートメントで自由変数なしでバインディングを行う方法は?

4

2 に答える 2

9

これはほぼ直訳であり、あなたの質問に答えるはずです。Scala のパターンの形式で存在する型クラスを使用しないため、完全に直接的ではありません。現在のケースでは、本当の理由なしに物事を過度に複雑にするだけだったからです。

case class LJ[A]( session : A ) {
  // See it as Haskell's "fmap"
  def map[B]( f : A => B ) : LJ[B] = 
    LJ( f( session ) )
  // See it as Haskell's ">>="
  def flatMap[B]( f : A => LJ[B] ) : LJ[B] =
    f( session )
}

type SimpleLJ = LJ[String]

def auth( a : String, b : String ) : SimpleLJ = ???

def readFeed( a : String ) : SimpleLJ = ???

def closeFeed( a : String ) : SimpleLJ = ???

def proceed : SimpleLJ = 
  auth("123", "456").flatMap(readFeed).flatMap(closeFeed)

// Same as above but using a for-comprehension, which is 
// used as a replacement for Haskell's "do"-block
def proceed2 : SimpleLJ = 
  for {
    a <- auth("123", "456")
    b <- readFeed(a)
    c <- closeFeed(b)
  } 
  yield c

このソリューションは、従来のオブジェクト指向アプローチを示しています。このアプローチでは、別のレベルで作業することになるため、return関数を型にカプセル化することはできませんLJ。型クラスのような型ではなく、型のインスタンスです。そのため、LJケース クラス コンストラクターは の対応物になりreturnます。

于 2013-03-01T06:58:55.997 に答える
4

ニキータの答えは慣用的な翻訳だと思いますが(理解のためのサポートなど、現実の状況では好まれるはずです)、それは間違いなく最も「直接的な」翻訳ではありません。

class LJ[A](val session : A)

trait Functor[F[_]] {
   def fmap[A,B](fa:F[A])(f:A => B) : F[B]
}

trait Monad[M[_]] {
   def pure[A](a:A):M[A]
   def bind[A,B](ma:M[A])(f:A => M[B]):M[B]
}

object LJFunctor extends Functor[LJ] {
  def fmap[A,B](lj:LJ[A])(f:A => B) = new LJ(f(lj.session))
}

object LJMonad extends Monad[LJ] {
   def pure[A](a:A) = new LJ(a)
   def bind[A,B](lj:LJ[A])(f:A => LJ[B]) = f(lj.session)
}


object MonadTest {

  type SimpleLJ = LJ[String]

  def auth(s:String, t:String):SimpleLJ = null

  def readFeed(s:String):SimpleLJ = null

  def closeFeed(s:String):SimpleLJ = null

  val proceed = LJMonad.bind(LJMonad.bind(auth("123","456"))(readFeed _))(closeFeed _)
}

(>>=)優れた演算子を取得するために、構文糖衣を上に追加できることに注意してください。

于 2013-03-01T14:47:20.510 に答える