首页 > 解决方案 > 是否可以在实例子句中使用`let in`?

问题描述

import Prelude hiding (Either (..))

data Tree a = Empty | Node a (Tree a) (Tree a)

instance Show a => Show (Tree a) where
  show t = show ST t

data ShowableTree a = ST Int (Tree a)

instance Show a => Show (ShowableTree a) where
  let
    indent 0 = ""
    indent n = "\t" ++ (indent n-1)
  in
    show (ST depth Empty) = (indent depth) ++ "()"
    show (ST depth (Node n l r)) =
      let
        stl = ST (depth+1) l
        str = ST (depth+1) r
      in
        (indent depth) ++ "(\n" ++ (indent depth) ++ (show n) ++ "\n" ++ (show stl) ++ "\n" ++ (show str) ++ "\n" ++ (indent depth) ++ ")\n"

这会吐出错误:

[m@green09 ~]$ ghci labn.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( labn.hs, interpreted )

labn.hs:14:3:
    parse error (possibly incorrect indentation or mismatched brackets)
Failed, modules loaded: none.

让我们试试where吧?

instance Show a => Show (ShowableTree a)
  where
    show (ST depth Empty) = (indent depth) ++ "()"
    show (ST depth (Node n l r)) =
      let
        stl = ST (depth+1) l
        str = ST (depth+1) r
      in
        (indent depth) ++ "(\n" ++ (indent depth) ++ (show n) ++ "\n" ++ (show stl) ++ "\n" ++ (show str) ++ "\n" ++ (indent depth) ++ ")\n"
    where
      indent 0 = ""
      indent n = "\t" ++ (indent n-1)

仍然没有成功:

[m@green09 ~]$ ghci labn.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
[1 of 1] Compiling Main             ( labn.hs, interpreted )

labn.hs:19:5: parse error on input `where'
Failed, modules loaded: none.

一种明确的解决方案是通过将定义移动到全局范围来污染indent全局范围。

但是,除此之外,是否有可能以某种方式定义indentwithin ShowableTree

标签: haskellcompiler-errorssyntax-error

解决方案


The body of an instance declaration is not an arbitrary expression; it's a list of function definitions. let can only be used where an expression is expected, and where has to be associated with a single equation. However, it's simple enough to define show with a single equation that would allow you to use either.

-- using where
instance Show a => Show (ShowableTree a) where
    show (ST depth t) = case t of
                         Empty -> indent depth ++ "()"
                         Node n l r -> let stl = ST (depth + 1) l
                                           str = ST (depth + 1) r
                                       in  indent depth ++ "(\n" ++ indent depth ++ show n ++ "\n" ++ show stl ++ "\n" ++ show str ++ "\n" ++ indent depth ++ ")\n"
        where indent = flip replicate '\t'

-- using let
instance Show a => Show (ShowableTree a) where
    show (ST depth t) = let indent = flip replicate '\t'
                        in case t of
                             Empty -> indent depth ++ "()"
                             Node n l r -> let stl = ST (depth + 1) l
                                               str = ST (depth + 1) r
                                           in  indent depth ++ "(\n" ++ indent depth ++ show n ++ "\n" ++ show stl ++ "\n" ++ show str ++ "\n" ++ indent depth ++ ")\n"

推荐阅读