首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Eff要求使用Debug.Trace.Trace行

Eff要求使用Debug.Trace.Trace行
EN

Stack Overflow用户
提问于 2014-07-16 14:01:41
回答 1查看 341关注 0票数 5

我正在编写从History.js到PureScript的绑定,并且仍然很难理解Eff、一行效果是什么以及它们为什么有价值。现在,我已经用EasyFFI编写了以下内容

代码语言:javascript
复制
type Title        = String
type Url          = String
type State        = forall a. {title :: Title, url :: Url | a}
type Data         = forall a. { | a}
type StateUpdater = Data -> Title -> Url -> Unit

-- this function is a work around for 'data' as a reserved word.
foreign import getData 
  "function getData(state){ return state['data']; }" 
  :: forall a b. { | a} -> b

unwrapState :: StateUpdater -> State -> Unit
unwrapState f s = f (getData s) s.title s.url

replaceState' :: StateUpdater
replaceState' = unsafeForeignProcedure ["data","title","url"] "History.replaceState(data,title,url)"
replaceState :: State -> Unit
replaceState = unwrapState replaceState'

foreign import data BeforeEach :: !
beforeEach :: forall e a. Eff e a ->  Eff (beforeEach :: BeforeEach | e) Unit
beforeEach = unsafeForeignProcedure ["fn",""] "window.beforeEach(fn);"

在后面的代码中,我有以下内容:

代码语言:javascript
复制
beforeEach $ do 
  replaceState {title = "wowzers!", url = "/foos"}

并得到以下错误

代码语言:javascript
复制
 Cannot unify Prelude.Unit with Control.Monad.Eff.Eff u2518 u2517.

我尝试过以各种方式操纵类型签名,试图将其全部排列起来,但我并不真正理解到底出了什么问题。所以在这一点上它只是猜测。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-16 16:12:06

我修改过的代码版本在这篇文章的末尾,但为了使其编译,我不得不做一些修改:

我假设您的StateUpdater会对浏览器历史产生影响,所以我将其类型更改为使用新的History效果类型的Eff monad。这是主要的问题,因为您的最后一行使用的是replaceState,其结果类型不是在Eff monad中。这导致了您看到的类型错误。

我将类型同义词中的一些普遍量化的类型变量移到函数类型中。我还移除了Data类型的同义词,并将数据内容移到State类型中的一个新的data字段中。

这一点很重要,因为以前的Data类型没有居民。有一个常见的误解(出于我不理解的原因),即forall a. { | a}是一种“我不关心字段”的记录类型。这是不正确的--这种类型表示包含可能存在的所有字段的记录类型,而且这种类型显然是无人居住的。从调用方的角度来看,forall a. {| a} -> r(forall a. {| a}) -> r之间有一个重要的区别。

在回答您最初的问题时:“什么是一行效果,以及它们为什么有用?”--行最初被添加到PureScript中,以处理记录类型上的多态性,而不必使用子类型。行允许我们向使用记录的函数提供多态类型,这样我们就可以将“记录的其余部分”作为类型系统中的一个概念来捕获。

在处理效果时,行也是一个有用的概念。就像我们不关心记录的其余部分是什么一样,我们通常不关心一组效果的其余部分是什么样子,只要所有的效果在类型系统中正确传播。

举个例子,我的修改代码涉及两个效果:History和您的BeforeEach。操作beforeEachreplaceState各自只使用这些效果之一,但它们的返回类型是多态的。这允许将main中的两个函数组合为两种效果,并正确键入。main的类型是forall eff. Eff (history :: History, beforeEach :: BeforeEach | eff) {},它是类型检查器推断的最一般的类型。

简而言之,效果系统中的行提供了一种处理各种“本机”效果交织的简洁方法,这样开发人员就不必担心效果的顺序或计算liftàla mtl之类的事情。

代码语言:javascript
复制
module Main where

import EasyFFI
import Control.Monad.Eff

type Title        = String
type Url          = String
type State d      = { title :: Title, url :: Url, "data" :: { | d } }

type StateUpdater d = forall eff. { | d } -> Title -> Url -> Eff (history :: History | eff) {}

foreign import data History :: !

unwrapState :: forall eff d. StateUpdater d -> State d -> Eff (history :: History | eff) {}
unwrapState f s = f s."data" s.title s.url

replaceState' :: forall d. StateUpdater d
replaceState' = unsafeForeignProcedure ["d","title","url"] "History.replaceState(d,title,url)"

replaceState :: forall eff d. State d -> Eff (history :: History | eff) {}
replaceState = unwrapState replaceState'

foreign import data BeforeEach :: !

beforeEach :: forall e a. Eff e a ->  Eff (beforeEach :: BeforeEach | e) {}
beforeEach = unsafeForeignProcedure ["fn",""] "window.beforeEach(fn);"

main = beforeEach $ do 
  replaceState { title: "wowzers!", url: "/foos", "data": {} }
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24782835

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档