여기에는 몇 가지 문제가 있습니다. 먼저, 중괄호 앞에 레코드 이름을 지정해야합니다. 그래서 지금
(>>=) (Val {getVal = l}) f = Val {getVal = map f l}
를 원하는, 당신의 기능 중 어느 것도 지금의 유형 체킹 것입니다. 그러나 이미 존재하는리스트 모나드 인스턴스에 위임하기 때문에 수정이 너무 어렵지 않습니다.
return
은 가깝지만 결과를 목록으로 묶어야합니다.
return x = Val [x]
마찬가지로, map
을 레코드 내에 포함하지 않을 것입니다. 당신은 (>>=)
의 목록 모나드 버전을 원합니다.
(>>=) (Val {getVal = l}) f = Val {getVal = l >>= f}
불행하게도, 이것은 아직도 아주의 유형 체킹, f
이후 Val
하지 []
를 반환하도록 설계되어 있습니다. 우리는 모나드 연산 내부에서 수정해야합니다.
(>>=) (Val {getVal = l}) f = Val {getVal = l >>= getVal . f}
그 후, 당신은 가능성이 Applicative
이 Monad
의 슈퍼 클래스 것에 대해 오류를 얻을 수 있습니다. 이는 일부 도우미 기능의 간단한 적용으로 해결할 수 있습니다.
import Control.Monad
-- ...
instance Functor Val where
fmap = liftM
instance Applicative Val where
pure = return
(<*>) = ap
이제 모든 사항이 컴파일되어야합니다. 당신이 GHC를 사용하는 경우 보조 노트로
은 자동으로
newtype
데이터 유형에 대한 당신에게 인스턴스를 줄 것이다
GeneralizedNewtypeDeriving
라는 편리한 기능이있다. 당신은
newtype
하지
data
에 너무
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Val a = Val {getVal :: [a]}
deriving (Show, Functor, Applicative, Monad)
이 유일한 작품처럼 사용할 수 있으며, 그것은 단지 GHC에서 작동하므로 휴대용에서 컴파일러 될 코드를하려는 경우 사용하지 마십시오.
'return'의 정의는 타입 체크가 아닙니다, 그렇습니까? – Carl