0

I was reviewing the code from https://github.com/input-output-hk/plutus-pioneer-program/blob/main/code/week05/src/Week05/NFT.hs and I don't understand why this section does not cause a compile error.

utxos <- utxosAt $ npAddress np
    case Map.keys utxos of
        []       -> Contract.logError @String "no utxo found"
        oref : _ -> do
utxosAt :: forall w s e. AsContractError e => Address -> Contract w s e (Map TxOutRef ChainIndexTxOut)
keys :: Map k v -> [k]

My expectation is that the variable utxos has type Contract w s e (Map TxOutRef ChainIndexTxOut). This should cause an error on Map.keys utxos, but it doesn't.

Edit: My code:

getNFT :: Wallet -> Value
        getNFT w = do
            utxos <- utxosAt $ mockWalletAddress w
            case getValue utxos of
                Just v -> v
                Nothing -> Ada.lovelaceValueOf 1000000

The type of getValue is getValue :: Map.Map TxOutRef ChainIndexTxOut -> Maybe Value

The errors I am getting are:

 error:
    • Couldn't match expected type ‘Value’
                  with actual type ‘Contract w0 s0 e0 b0’
    • In a stmt of a 'do' block: utxos <- utxosAt $ mockWalletAddress w
      In the expression:
        do utxos <- utxosAt $ mockWalletAddress w
           case getValue utxos of
             Just v -> v
             Nothing -> lovelaceValueOf 1000000
      In an equation for ‘getNFT’:
          getNFT w
            = do utxos <- utxosAt $ mockWalletAddress w
                 case getValue utxos of
                   Just v -> v
                   Nothing -> lovelaceValueOf 1000000
    |
179 |             utxos <- utxosAt $ mockWalletAddress w
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Compilation Error, Line 181, Column 27 (jump)
 error:
    • Couldn't match expected type ‘Contract w0 s0 e0 b0’
                  with actual type ‘Value’
    • In the expression: v
      In a case alternative: Just v -> v
      In a stmt of a 'do' block:
        case getValue utxos of
          Just v -> v
          Nothing -> lovelaceValueOf 1000000
    |
181 |                 Just v -> v
    |                           ^
Compilation Error, Line 182, Column 28 (jump)
 error:
    • Couldn't match expected type ‘Contract w0 s0 e0 b0’
                  with actual type ‘Value’
    • In the expression: lovelaceValueOf 1000000
      In a case alternative: Nothing -> lovelaceValueOf 1000000
      In a stmt of a 'do' block:
        case getValue utxos of
          Just v -> v
          Nothing -> lovelaceValueOf 1000000
    |
182 |                 Nothing -> Ada.lovelaceValueOf 1000000
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^

1 Answer 1

0

The entire computation is in the Contract monad and we use the do notation. Thus when we write utxos <- utxosAt $ npAddress np, the type of utxos is Map TxOutRef ChainIndexTxOut, so everything typechecks.

A simpler example:

import Text.Read
plusOne :: String -> Maybe Integer
plusOne s = do
 x <- readMaybe s :: Maybe Integer
 return $ x + 1

The type of readMaybe is (here) String -> Maybe Integer, but since we are after do, x is of type Integer, not Maybe Integer. So plusOne "3" is Just 4.

7
  • Thank you for taking the time to help me. I verified your response, read up on do notation and decided to try using this concept in my own project. I'm not getting the results I expected and edited my original post in hopes you could take a look for me. Feb 23, 2022 at 19:12
  • The problem is that getNFT :: Wallet -> Value and Value is not a Monad, so you can't use the do notation there. Also,utxosAt is a computation in the Contract monad, so maybe you want to change to getNFT :: Wallet -> Contract w s e Value, where you might have concrete types for the variables w, s, e. Then you should also have return v on one case branch, and accordingly return on the other branch. Feb 23, 2022 at 19:57
  • I'm not sure this is the right place, but I'll explain a bit more: if you write a function f :: String -> Integer you can't use do - it's just for instances of the Monad class. Also, you can't mix the monads: in a function g :: a -> Maybe b you can use do but you can't write x <- h y where h :: y -> m x and m is another monad than Maybe - note that I use y both for a type and a value of that type, to simplify matters. Feb 23, 2022 at 20:09
  • through your advice I was able to fix my functions and gain a better understanding of how Monads work. Having my function getNFT return a Contract monad causes another problem for me because I need to pass the Value in Contract w s e Value into mustPayToPubKey :: forall i o. PaymentPubKeyHash -> Value -> TxConstraints i o Feb 25, 2022 at 15:03
  • If you share your whole code with me, I'll try to help. I would guess you must replace a let v = getNFT ... with v <- getNFT ..., as mint is in the Contract monad already. Feb 25, 2022 at 16:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.