Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 如何显式指定中间变量的类型?_Haskell - Fatal编程技术网

Haskell 如何显式指定中间变量的类型?

Haskell 如何显式指定中间变量的类型?,haskell,Haskell,我有一个函数readConfigFromEnv,它从环境变量中读取一些环境变量 readConfigFromEnv :: IO (Int, String) readConfigFromEnv = do portStr <- getEnv "PORT" let port = read portStr secret <- getEnv "SECRET" return (port, secret) readConfigFromEnv::IO(Int,String) rea

我有一个函数
readConfigFromEnv
,它从环境变量中读取一些环境变量

readConfigFromEnv :: IO (Int, String)
readConfigFromEnv = do
  portStr <- getEnv "PORT"
  let port = read portStr
  secret <- getEnv "SECRET"
  return (port, secret)
readConfigFromEnv::IO(Int,String)
readConfigFromEnv=do

portStr没有
ScopedTypeVariables
您可以为声明块中引入的变量添加类型签名,如do块中的
let
语句,
let。。。在…
表达式和
where
子句中。不过,您在示例中猜到的语法并不完全正确,您需要在变量定义之外添加一个单独的类型声明(与您在其定义之外的单独一行上编写
readconfigfromnv::IO(Int,String)
的方式完全相同,而不是同时作为
readconfigfromnv::IO写入(Int,String)=do
)。例如,您可以编写:

readConfigFromEnv :: IO (Int, String)
readConfigFromEnv = do
  portStr <- getEnv "PORT"
  let port :: Int
      port = read portStr
  secret <- getEnv "SECRET"
  return (port, secret)
这里,类型表达式
x,y::a
表示
x
y
属于出现在
readtwoothings
的类型签名中的
a

比较删除所有a.
和/或将
ScopedTypeVariables
替换为
ExplicitForAll
时发生的情况。在这种情况下,您会得到一个错误,因为
a
x
y
类型中的
a
readtwoothings
类型中的
不同。

在实践中,我发现
ScopedTypeVariables
行为通常是您实际希望发生的,但因为您可以找到这样的示例,其中相同的代码意味着两种不同的事情,这取决于是否启用了
ScopedTypeVariables
(您甚至可以构造代码以任何方式编译并执行不同操作的示例!),您不能盲目地打开它而不了解它如何影响类型签名


现在,有了这些背景知识,下面是我对你的问题清单的明确回答:

  • 是如果要声明声明每个局部变量的类型,则需要
    ScopedTypeVariables


  • 明确指定每个顶级定义的类型是一个非常常见的建议,我想说这几乎是Haskell社区的共识。我还发现在
    let
    where
    绑定变量中添加类型声明很有帮助,如果它们很复杂,但这种做法不太普遍。添加类型对于没有
    ScopedTypeVariables
    portStr之类的东西,您可以为声明块中引入的变量添加类型签名,例如do块中的
    let
    语句、
    let…in…
    表达式和
    where
    子句。不过,您在示例中猜测的语法并不完全正确,您不需要这样做o添加一个单独的类型声明来声明变量的定义(与您在其定义之外的单独一行上编写
    readConfigFromEnv::IO(Int,String)
    的方式完全相同,而不是像
    readConfigFromEnv::IO(Int,String)=do那样同时编写这两个变量。因此,您可以,例如,编写:

    readConfigFromEnv :: IO (Int, String)
    readConfigFromEnv = do
      portStr <- getEnv "PORT"
      let port :: Int
          port = read portStr
      secret <- getEnv "SECRET"
      return (port, secret)
    
    这里,类型表达式
    x,y::a
    表示
    x
    y
    属于出现在
    readtwoothings
    的类型签名中的
    a

    比较删除所有a.
    和/或将
    ScopedTypeVariables
    替换为
    ExplicitForAll
    时发生的情况。在这种情况下,您会得到一个错误,因为
    a
    x
    y
    类型中的
    a
    readtwoothings
    类型中的
    不同。

    在实践中,我发现
    ScopedTypeVariables
    行为通常是您实际希望发生的,但因为您可以找到这样的示例,其中相同的代码意味着两种不同的事情,这取决于是否启用了
    ScopedTypeVariables
    (您甚至可以构造代码以任何方式编译并执行不同操作的示例!),您不能盲目地打开它而不了解它如何影响类型签名


    现在,有了这些背景知识,下面是我对你的问题清单的明确回答:

  • 是如果要声明声明每个局部变量的类型,则需要
    ScopedTypeVariables


  • 明确指定每个顶级定义的类型是一个非常常见的建议,我想说这几乎是Haskell社区的共识。我还发现在
    let
    where
    绑定变量中添加类型声明很有帮助,如果它们很复杂,但这种做法不太普遍。添加类型对于像
    portStr这样的事情,您可以在
    portStr中指定类型,例如
    portStr
    。注意:我上面评论的最后一个例子中的歧义也可以通过
    TypeApplications
    解决,也就是说
    x还要添加一件事情,您可以指定类型,例如
    portStr
    portStr中注意:我上面评论的最后一个例子中的模糊性也可以通过
    TypeApplications
    解决,也就是说
    x要添加两条注释:使用
    readIO
    而不是
    read
    在格式错误的输入上立即强制崩溃,而不是在
    端口
    是第一个实际使用的;您总是可以将类型签名移动到另一端,如
    let port=read portStr::Int
    (或者
    端口谢谢@DanielWagner。在某些情况下,我的Monad是一个类型类,而不是concreate类型,我可以将类型签名放在另一侧。例如,如果我使用MonadIO或ReaderT,我只知道Monad将返回字符串,但我不知道Monad具体是什么
    
    {-# LANGUAGE ScopedTypeVariables #-}
    
    readTwoThings :: forall a. Read a => IO (a, a)
    readTwoThings = do
      sx <- readLn
      sy <- readLn
      let x, y :: a
          x = read sx
          y = read sy
      pure (x, y)