如何编写宏(平均n1 n2 n3 ...)来计算数字的平均值

时间:2016-03-08 22:52:57

标签: clojure macros

我想使用defmacro来计算数字列表的平均值。它应该像这样运行:

Internal .Net Framework Data Provider error 6. 
Description: An unhandled exception occurred during the execution of the  current web request. Please review the stack trace for more information about the error and where it originated in the code. 

 Exception Details: System.InvalidOperationException: Internal .Net Framework Data Provider error 6.

Source Error: 


 An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  

Stack Trace: 



[InvalidOperationException: Internal .Net Framework Data Provider error 6.]
System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection) +347
    System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) +78
    System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection) +191
    System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) +154
    System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) +21
    System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry) +90
    System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) +217
    System.Data.SqlClient.SqlConnection.Open() +96


    System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.<Open>b__36(DbConnection t, DbConnectionInterceptionContext c) +10
            System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch(TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed) +72
           System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext) +360
        System.Data.Entity.Core.EntityClient.EntityConnection.<Open>b__2() +55
        System.Data.Entity.SqlServer.<>c__DisplayClass1.<Execute>b__0() +10
         System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Func`1 operation) +189
       System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation) +78
       System.Data.Entity.Core.EntityClient.EntityConnection.Open() +253

       [EntityException: The underlying provider failed on Open.]
   System.Data.Entity.Core.EntityClient.EntityConnection.Open() +323
   System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions) +133
   System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction(Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess) +46
   System.Data.Entity.Core.Objects.<>c__DisplayClass7.<GetResults>b__5() +154
   System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Func`1 operation) +189
   System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) +279
   System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0() +11
   System.Data.Entity.Internal.LazyEnumerator`1.MoveNext() +45
   System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source) +121
   System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1(IEnumerable`1 sequence) +40
   System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable`1 query, Expression queryRoot) +60
   System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) +113
   System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(Expression expression) +113
   System.Linq.Queryable.FirstOrDefault(IQueryable`1 source) +211
   System.Data.Entity.Internal.EdmMetadataRepository.QueryForModelHash(Func`2 createContext) +285
   System.Data.Entity.Internal.InternalContext.QueryForModelHash() +198
   System.Data.Entity.Internal.ModelCompatibilityChecker.CompatibleWithModel(InternalContext internalContext, ModelHashCalculator modelHashCalculator, Boolean throwIfNoMetadata, DatabaseExistenceState existenceState) +84
   System.Data.Entity.Internal.InternalContext.CompatibleWithModel(Boolean throwIfNoMetadata, DatabaseExistenceState existenceState) +54
   System.Data.Entity.CreateDatabaseIfNotExists`1.InitializeDatabase(TContext context) +117
   System.Data.Entity.Internal.<>c__DisplayClassf`1.<CreateInitializationAction>b__e() +76
   System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) +60

[DataException: An exception occurred while initializing the database. See the InnerException for details.]
   System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action) +122
   System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization() +357
   System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c) +7
   System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input) +110
   System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action) +198
   System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase() +73
   System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) +28
   System.Data.Entity.Internal.Linq.InternalSet`1.Initialize() +53
   System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext() +15
   System.Data.Entity.Internal.Linq.InternalSet`1.ExecuteSqlQuery(String sql, Boolean asNoTracking, Nullable`1 streaming, Object[] parameters) +96
   System.Data.Entity.Internal.InternalSqlSetQuery.GetEnumerator() +42
   System.Data.Entity.Infrastructure.DbRawSqlQuery`1.GetEnumerator() +30
   System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +369
   System.Linq.Enumerable.ToList(IEnumerable`1 source) +58
   Login.Controllers.HomeController.Index(String error) +283
   lambda_method(Closure , ControllerBase , Object[] ) +104
   System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +14
   System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +182
   System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +27
   System.Web.Mvc.Async.<>c__DisplayClass42.<BeginInvokeSynchronousActionMethod>b__41() +28
   System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +10
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +32
   System.Web.Mvc.Async.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33() +58
   System.Web.Mvc.Async.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49() +225
   System.Web.Mvc.Async.<>c__DisplayClass37.<BeginInvokeActionMethodWithFilters>b__36(IAsyncResult asyncResult) +10
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +34
   System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +24
   System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +99
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +27
   System.Web.Mvc.<>c__DisplayClass1d.<BeginExecuteCore>b__18(IAsyncResult asyncResult) +14
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +16
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +36
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +16
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +26
   System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +10
   System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__3(IAsyncResult asyncResult) +25
   System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +16
   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +50
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +28
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9644037
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

我的代码是:

user=> (avg 1 2 3 4 5 6)
3.5

但是我收到了一个错误:

(defmacro ave [& number]
   `(float `(/ `(reduce + ~number) `(count ~number))))

我该如何解决?感谢

2 个答案:

答案 0 :(得分:2)

正如合金建议的那样,最好的解决方案是功能:

(ns clj.core
  (:require [clojure.string :as str] )
  (:use tupelo.core))

(defn avg
  "Compute the average of 1 or more vals."
  [& values]
  (when (zero? (count values)) 
    (throw (IllegalArgumentException. "avg: error - at least 1 value required")))
  (let [total   (apply + values)
        result  (double (/ total (count values))) ]
    result))

它的测试:

(ns tst.clj.core
  (:use clj.core 
        clojure.test 
        tupelo.core))

(deftest t-avg
  (is (thrown? IllegalArgumentException (avg)))
  (is (= 1.0 (avg 1)))
  (is (= 1.5 (avg 1 2)))
  (is (= 2.0 (avg 1 2 3)))
  (is (= 2.5 (avg 1 2 3 4))))

请注意,该函数比宏更强大,因为宏不能作为参数传递给高阶函数(例如滤镜,贴图等)。

答案 1 :(得分:1)

你应该使用一个包含整个表达式的语法引用,并将你的数字的unquote-splicing作为list参数。除此之外,由于reducecount接受列表作为参数,我使用list来包装它们。所以,试试:

(defmacro ave [& number] 
  `(float(/ (reduce + (list ~@number)) (count (list ~@number)))))

在REPL中产生:

user=> (ave 1 2 3 4 5 6)
3.5

更新:根据评论中amalloy指出的错误,这是我的第二个版本:

(defmacro ave [& number] 
  `(let [ns# (list ~@number)] 
     (float (/ (reduce + ns#) (count ns#)))))

我在REPL中的测试:

user=> (ave (do (println "Doing a lot of work...") 1) 2 3 4 5 6)
Doing a lot of work...
3.5